哈希映射的设计问题?

有一个哈希映射的需求,就是将 若干维度 映射到 唯一值(暂不考虑碰撞)

即 f(a,b,c....)=uniqueId

如果只是实现这个,那么我选择一个 性能以及冲突少的 hash 算法即可,可是还有另外一个需求:

假如我现在有 如下映射:

f(a, b) = u1
f(a, c) = u2
f(x, y) = v1

前提:f(a, b) != f(b, a)

如果我想实现 f(a) = [u1, u2] ,即 映射出来 以 a 为前缀的所有 映射结果,有没有比较好的方式?

目前想到的:

方式一:

根据 前缀 a  查询出 所有以 a 为前缀的 结果(即  a,b    a,c),然后再分别 以这个结果去映射

方式二:

事先定义出我有查询 a 前缀的需求,那么在 f 这个映射函数上做手脚,即 如果输入 f(a, b),那么就产生  f(a), f(a, b)的映射并存储关联;如果输入f(a, c)就产生 f(a), f(a, c)的结果进行存储,那么再查询 f(a)时,就能以  f(a)的映射值查询出 之前关联的所有 f(a,b), f(a, c)的映射集合了

还有其他比较好的方式吗?

阅读 2.2k
2 个回答

在 Java 中可以使用一个 Map 对象来实现哈希映射表,key 是一个包含所有维度的复合键对象,value 则是对应的唯一值。

对于第二个需求,可以使用 Java 8 中引入的 Stream API,结合 Lambda 表达式来实现。

具体的实现步骤如下:

1、定义一个包含所有维度的复合键类(可以使用 Java Bean 或者普通的 POJO 类)。
2、实现复合键类的 hashCode 和 equals 方法,以确保哈希映射表的正确性。
3、定义一个 Map 对象来维护哈希映射表。
4、查询以某个维度为前缀的所有映射结果时,使用 Stream API 进行过滤和映射。

下面是一个示例代码:

import java.util.*;
import java.util.stream.*;

class Dimension {
    private String a, b, c;

    // Getters and setters omitted for brevity.

    @Override
    public int hashCode() {
        return Objects.hash(a, b, c);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof Dimension)) {
            return false;
        }
        Dimension other = (Dimension)obj;
        return Objects.equals(a, other.a) &&
               Objects.equals(b, other.b) &&
               Objects.equals(c, other.c);
    }
}

public class HashMapDemo {
    public static void main(String[] args) {
        Map<Dimension, String> hashMap = new HashMap<>();
        hashMap.put(new Dimension() {{ setA("a"); setB("b"); }}, "u1");
        hashMap.put(new Dimension() {{ setA("a"); setC("c"); }}, "u2");
        hashMap.put(new Dimension() {{ setA("x"); setB("y"); }}, "v1");

        String[] result = hashMap.entrySet().stream()
                .filter(entry -> Objects.equals(entry.getKey().getA(), "a"))
                .map(Map.Entry::getValue)
                .toArray(String[]::new);
        System.out.println(Arrays.toString(result));  // 输出 [u1, u2]
    }
}

我跟楼上想法类似,但更偏向于直接对象封装。


@Getter
@EqualsAndHashCode(of = "a")
public class Demo {
    private String a;
    private String b;
    private int innerHash;

    public Demo(String a, String b) {
        this.a = a;
        this.b = b;
        this.innerHash = Objects.hash(a, b);
    }

    public static void main(String[] args) {
        Demo ab = new Demo("a", "b");
        Demo ac = new Demo("a", "c");
        Demo ba = new Demo("b", "a");
        Demo xy = new Demo("x", "y");

        Map<String, List<Demo>> map = Arrays.asList(ab, ac, ba, xy)
                .stream()
                .collect(Collectors.groupingBy(Demo::getA));

        List<Integer> hashs = map.get("a").stream().map(Demo::getInnerHash).collect(Collectors.toList());
        System.out.println("a#hashs = " + hashs);
        System.out.println("b#hashs = " + hashs);

    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题