26

哈希表中的同一个键是否可以有多个值?如果没有,你能推荐任何可以使用的类或接口吗?

4

13 回答 13

21

不,这就是哈希表的想法。

但是,如果列表不存在,您可以使用 aMap<YourKeyObject, List<YourValueObject>>和一些实用方法创建列表,或者使用类似Multimap来自Google Collections的方法。

例子:

String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"

请注意,这Multimap并不完全等同于自制解决方案;Hashtable同步它的所有方法,但Multimap不做这样的保证。这意味着如果您在多个线程上使用它Multimap,使用 a可能会给您带来问题。如果您的地图仅在一个线程上使用,那将没有什么区别(并且您应该一直使用而不是无论如何)。HashMapHashtable

于 2009-06-26T15:42:49.217 回答
11

哈希表的值是对象,因此您可以存储列表

于 2009-06-26T15:42:58.310 回答
9

在哈希表中,人们将使用键/值对来存储信息。

在 Java 中,Hashtable类接受单个键的单个值。以下是尝试将多个值关联到单个键的示例:

Hashtable<String, String> ht = new Hashtable<String, String>();

ht.put("Answer", "42");
ht.put("Hello", "World");    // First value association for "Hello" key.
ht.put("Hello", "Mom");      // Second value association for "Hello" key.

for (Map.Entry<String, String> e : ht.entrySet()) {
  System.out.println(e);
}

为了尝试将多个值 ( "World", "Mom") 包含到单个键 ( "Hello") 中,我们最终得到以下结果,用于打印 中的条目Hashtable

Answer=42
Hello=Mom

"Hello"and的键/值对"World"不在Hashtable- 只有第二个"Hello"和“ Mom”条目在Hashtable. 这表明不能有多个值与Hashtable.


这里真正需要的是一个multimap,它允许将多个值关联到一个键。

多地图的一种实现Multimap来自Google Collections

Multimap<String, String> mm = HashMultimap.create();

mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");

for (Map.Entry<String, String> e : mm.entries()) {
  System.out.println(e);
}

这类似于上面使用的示例Hashtable,但行为完全不同——aMultimap允许将多个值关联到单个键。执行上述代码的结果如下:

Answer=42
Hello=Mom
Hello=World

可以看出,对于"Hello"键,它的值"Mom""World"与之关联的值。与 不同Hashtable,它不会丢弃其中一个值并将其替换为另一个值。Multimap能够为每个键保留多个值。

于 2009-06-26T16:36:11.653 回答
7

与其给出另一个 multipmap 答案,不如问你为什么要这样做?

多个值是否相关?如果是,那么最好创建一个数据结构来保存它们。如果不是,那么使用单独的地图可能更合适。

您是否将它们放在一起以便可以根据密钥对其进行迭代?您可能想要寻找另一种索引数据结构,例如 SkipList。

于 2009-06-26T15:57:47.523 回答
5

只需制作自己的:

Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();

添加:

  public void add(String key, Object o) {
    List<Object> list;
    if (multiMap.containsKey(key)) {
      list = multiMap.get(key);
      list.add(o);
    } else {
      list = new ArrayList<Object>();
      list.add(o);
      multiMap.put(key, list);
    }
  }
于 2009-06-26T21:00:50.093 回答
5

正如其他人指出的那样,没有。相反,请考虑使用Multimap可以为同一个键映射多个值的 a。

Google Collections ( update : Guava )库包含一个实现,可能是您最好的选择。

编辑:当然,您可以按照Eric 的建议进行操作,并将 Collection 作为值存储在您的 Hashtable(或 Map,更一般地说)中,但这意味着您自己编写不必要的样板代码。当使用像 Google Collections 这样的库时,它会为你处理低级的“管道”。查看这个很好的示例,了解如何通过使用 Multimap 而不是 vanilla Java Collections 类来简化您的代码。

于 2009-06-26T15:45:34.547 回答
4

没有一个答案表明我首先会做什么。

我在 OO 能力方面取得的最大飞跃是当我决定总是开设另一个课程时,它似乎甚至可能有点用——这是我从遵循这种模式中学到的东西之一。

几乎一直,我发现我试图放入哈希表的对象之间存在关系。通常情况下,有一个类的空间——甚至是一两个方法。

事实上,我经常发现我什至不需要 HashMap 类型的结构——一个简单的 HashSet 就可以了。

您作为主键存储的项目可以成为新对象的标识——因此您可以创建仅引用该对象的 equals 和 hash 方法(eclipse 可以轻松地为您创建 equals 和 hash 方法)。这样,新对象将与原始对象完全一样保存、排序和检索,然后使用属性来存储其余项目。

大多数时候,当我这样做时,我发现也有一些方法可以去那里,在我知道之前,我有一个应该一直在那里但我从未认出的成熟对象,还有一堆垃圾我的代码中的因素。

为了使它更像是一个“婴儿步骤”,我经常创建包含在我的原始类中的新类——有时我什至将这个类包含在一个方法中,如果这样定义它是有意义的——然后我移动它随着它变得更加清晰,它应该是一流的。

于 2009-06-26T16:10:54.047 回答
2

简单的。而不是 Hashtable<Key, Value>,使用Hashtable<Key, Vector<Value>>.

于 2009-06-26T15:44:19.213 回答
2

有关多地图和类似的此类收藏,请参阅Google 收藏库。内置集合对此没有直接支持。

于 2009-06-26T15:45:20.413 回答
2

您正在寻找的是Multimapgoogle collections api提供了一个很好的实现,还有很多值得学习使用的东西。强烈推荐!

于 2009-06-26T15:57:49.970 回答
1

您需要使用称为MultiMap的东西。这不是严格意义上的地图,但它是一个不同的 API。它与 Map<K, List<V>> 大致相同,但您不会有像 entrySet() 或 values() 这样的方法。

于 2009-06-26T15:44:16.733 回答
0

以下代码没有 Google 的 Guava 库。它用于双值作为键和排序顺序

Map<Double,List<Object>> multiMap = new TreeMap<Double,List<Object>>();

for( int i= 0;i<15;i++)
{
    List<Object> myClassList = multiMap.get((double)i);
    if(myClassList == null)
    {
        myClassList = new ArrayList<Object>();
        multiMap.put((double) i,myClassList);
    }
    myClassList.add("Value "+ i);
}

List<Object> myClassList = multiMap.get((double)0);
if(myClassList == null)
{
    myClassList = new ArrayList<Object>();
    multiMap.put( (double) 0,myClassList);
}
myClassList.add("Value Duplicate");
for (Map.Entry entry : multiMap.entrySet()) 
{
  System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue());
}
于 2013-02-14T15:53:14.807 回答
0

除了 Google Collections 之外,还有一个用于 MultiMap的apache Commons Collection对象

于 2010-10-07T09:12:09.567 回答