Java中多个键对应单个值的映射

20

我认为我的问题与这个问题类似:如何使用多个键实现Map? 但有一个重要的区别。在那个问题中(如果我理解正确,请让我知道如果不是),键应该始终是唯一的。我想要一个形式为: MyMap 的Map,其中键不一定是唯一的。如果这没有意义,我基本上想要一个二维数组,但不是通过坐标引用元素,而是通过对象对来引用它们。

有人有任何关于某个库适合这种需求或者自己实现它的好方法吗?就库而言,我已经看过Apache Commons和Guava,两者都似乎不符合我的要求。


4
地图的整个概念是独特的键-值对,想要打破这个概念意味着你应该从一开始就使用不同的存储对象。你能举一个“通过对象对来引用元素”的例子吗?这可能会对我有所帮助。 - Grambot
1
你有没有看过Guava库中的MultiMap? - Alexander Pogrebnyak
我已经看过MultiMap了,那不是我想要的。 你说得很对,我想要的不是一个map,我会研究下面答案中提到的Table结构,这是我之前没有见过的东西。 但是为了回答你的问题,就像你在原始的2D数组中引用元素一样:array[0][1],我想能够做到:array[obj1][obj2] 并将其映射到一个值(显然使用不同的语法,这就是我要实现的功能)。 - Steve
在常规映射中使用https://dev59.com/SHVC5IYBdhLWcg3w4VVz对吗? - Per Alexandersson
4个回答

22

Guava中的Table数据结构似乎符合您使用一对对象引用值的需求。


1
但仅仅为了使用Table数据结构添加Guava库是不值得的,因为它有大约15000个方法,其中并不是全部都有用。 - shekar

14
我希望这个答案不会被视为牢骚,而是据我所知,您想使用一个库来完成可以在jdk中轻松实现的事情。
无论如何,您提到希望使用一对对象访问元素。您可以创建一个将键保存为成员变量的类,例如:
public class Pair {
  // string represntation of an object
  private final String x; 
  private final String y;

  // ctor, getters...

  public int hashcode() {...}
  public boolean equals(Object other) {...}
}
hashcode方法会为所有包含的元素(在此例中是两个元素xy,但可以轻松扩展以支持任意数量的元素)生成哈希码。如果两个键具有相同的xy值,则它们将是相同的。如果您的键值对元素不是简单字符串,则很容易派生出几乎任何对象的字符串表示(例如提供一个良好实现的toString方法)。
其思想是对于键值对中的每个元素都有唯一的字符串表示。
当然,生成可靠的哈希码并不是件容易的事,所以一个出色的选择是使用字符串。要生成哈希码,您只需将您的键值对对象的字符串表示连接起来即可:
public int hashcode() {
  return ('x' + x + ":y" + y).hashcode();
}

请确保提供一些分隔符。否则,对于像 x=ab, y=bx=a, y=bb 这样的值,即使对象完全不同,您也会得到相同的哈希码。

而检查一对元素的值是否相等就像轻而易举一样:

public boolean equals(Object other) {
  // if other is not null and is an instance of Pair
  final Pair otherPair = (Pair)other;
  return this.x.equals(otherPair.x) && this.y.equals(otherPair.y);
}

现在,你可以将你的 Pair 类用于映射中,例如:

final Map<Pair, Whatever> map = new Hashmap<Pair, Whatever>();
// ...

基本上,HashMap通过使用键的哈希码来确定值应分配到哪个存储桶中。如果两个键具有相同的哈希码,那么将使用equals方法来确定是发生了冲突还是它们是相同的键。

如果您想在TreeMap中使用您的Pair类,则必须实现compareTo方法或在实例化此类映射时提供自己的比较器。 TreeMap实现依赖于compareTo方法的结果来确定值应该分配到何处。


2
我的答案被接受了,建议使用下面的Guava Table类,因为这似乎比编写/测试/调试自己的自定义数据结构更容易。然而-仍然因为同样优秀的解决方案而被点赞,谢谢。 - Steve
等于和重写方法对我不起作用。我使用了Eclipse生成的方法,它完美地工作了。源代码>生成hashCode()和equals()。 - aldo.roman.nurena
给一个赞因为……“我希望这个答案不会被看作是一通牢骚”。 - Snoop

3

Apache Commons Collections拥有MultiKey功能。

import org.apache.commons.collections4.keyvalue.MultiKey;

Map<MultiKey, ValueType> myMap = new HashMap<MultiKey, ValueType>();
myMap.put(new MultiKey(key1, key2), value);

myMap.get(new MultiKey(key1, key2));

它的好处是可以从Map创建N维数组。


2

我觉得你在寻找一个嵌套的HashMap。这个方法可以行得通,但我的直觉告诉我实现这样的“怪物”会是一个可怕的想法,无论是性能方面还是理智方面。

下面是初始化的方法:

    HashMap<Key1, HashMap<Key2, Value>> nestedHashMap = new HashMap<Key1, HashMap<Key2, Value>>();

添加数值:

    Key1 first;
    Key2 second;
    Value data;
    HashMap<Key2, Value> tempMap = new HashMap<Key2, Value>();
    tempMap.put(second, data);
    nestedHashMap.put(first, tempMap);

取回数据:

    Key1 first;
    Key2 second;
    Value data;
    data = nestedHashMap.get(first).get(second);

免责声明:此代码尚未经过测试,仅是我脑海中的想法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接