Java中的多值哈希表
是否可以在哈希表中为同一个键设置多个值? 如果没有,你能建议任何可以使用的类或接口吗?
不,这就是哈希表的想法。
但是,您可以使用Map
和一些用于创建列表的实用程序方法(如果它不存在)来滚动您自己的方法,或使用类似Google Collections的Multimap
。
例:
String key = "hello"; Multimap 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
,使用Multimap
可能会导致问题。 如果你的地图只在一个线程上使用,它就没有区别(你应该使用HashMap
而不是Hashtable
)。
哈希表的值是Object,因此您可以存储List
而不是给出另一个多重映射答案,我会问你为什么要这样做?
多个值是否相关? 如果是,那么创建一个数据结构来保存它们可能会更好。 如果不是,那么使用单独的地图可能更合适。
您是否将它们保持在一起,以便您可以根据密钥对它们进行迭代? 您可能希望寻找替代索引数据结构,如SkipList。
在哈希表中,可以使用键/值对来存储信息。
在Java中, Hashtable
类接受单个键的单个值。 以下是尝试将多个值关联到单个键的示例:
Hashtable ht = new Hashtable(); 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 e : ht.entrySet()) { System.out.println(e); }
为了将多个值( "World"
, "Mom"
)包含到单个键( "Hello"
)中,我们最终得到以下结果来打印Hashtable
的条目:
Answer=42 Hello=Mom
"Hello"
和"World"
的键/值对不在Hashtable
– 只有第二个"Hello"
和“ Mom
”条目在Hashtable
。 这表明不能将多个值与Hashtable
的单个键相关联。
这里真正需要的是一个multimap ,它允许将多个值关联到一个键。
多图的一个实现是来自Google Collections的 Multimap
:
Multimap mm = HashMultimap.create(); mm.put("Answer", "42"); mm.put("Hello", "World"); mm.put("Hello", "Mom"); for (Map.Entry e : mm.entries()) { System.out.println(e); }
这类似于上面使用Hashtable
的示例,但行为完全不同 – Multimap
允许将多个值关联到单个键。 执行上述代码的结果如下:
Answer=42 Hello=Mom Hello=World
可以看出,对于"Hello"
键, "Mom"
和"World"
与之关联。 与Hashtable
不同,它不会丢弃其中一个值并将其替换为另一个值。 Multimap
能够保留每个键的多个值。
正如其他人指出的那样,没有。 相反,请考虑使用Multimap
,它可以为同一个键映射许多值。
Google Collections ( 更新 : Guava )库包含一个实现,可能是您最好的选择。
编辑 :当然你可以像Eric建议的那样做,并将Collection作为值存储在你的Hashtable(或更普遍的Map)中,但这意味着自己编写不必要的样板代码。 使用Google Collections这样的库时,会为您处理低级别的“管道”。 看看这个很好的例子 ,说明如何使用Multimap而不是vanilla Java Collections类简化代码。
没有一个答案表明我先做什么。
我在OO能力方面取得的最大跳跃是当我决定在看起来它甚至可能稍微有用的时候总是制作另一个课程 – 这是我从遵循该模式学到的东西之一。
几乎所有时间,我发现我试图放入哈希表的对象之间存在关系。 通常,有一个class级的空间 – 甚至是一两种方法。
事实上,我经常发现我甚至不想要一个HashMap类型结构 – 一个简单的HashSet就可以了。
您作为主键存储的项目可以成为新对象的标识 – 因此您可以创建仅引用该对象的equals和hash方法(eclipse可以轻松地为您创建equals和hash方法)。 这样,新对象将像原始对象一样保存,排序和检索,然后使用属性存储其余项目。
大多数时候,当我这样做时,我发现有一些方法可以去那里,在我知道它之前我有一个完整的对象应该一直存在但我从来没有认识到,和一堆垃圾我的代码中的因素。
为了使它更像是一个“宝贝步骤”,我经常创建包含在我的原始类中的新类 – 有时我甚至在方法中包含类,如果它以这种方式限定它 – 那么我移动它因为它变得更加清晰,它应该是一流的课程。
做你自己的:
Map
加上:
public void add(String key, Object o) { List list; if (multiMap.containsKey(key)) { list = multiMap.get(key); list.add(o); } else { list = new ArrayList(); list.add(o); multiMap.put(key, list); } }
有关多图和类似此类集合的信息,请参阅Google Collections Library 。 内置集合没有直接支持。
您正在寻找的是Multimap 。 谷歌collectionsapi提供了很好的实现,以及其他值得学习使用的东西。 强烈推荐!
你需要使用一种叫做MultiMap的东西。 这不是严格意义上的Map,但它是一个不同的API。 它与Map
简单。 而不是Hashtable
,使用Hashtable
。
除了Google Collections之外,还有一个用于MultiMap的apache Commons Collection对象
以下代码没有Google的Guava库。 它用于双值作为键和排序顺序
Map> multiMap = new TreeMap>(); for( int i= 0;i<15;i++) { List myClassList = multiMap.get((double)i); if(myClassList == null) { myClassList = new ArrayList(); multiMap.put((double) i,myClassList); } myClassList.add("Value "+ i); } List myClassList = multiMap.get((double)0); if(myClassList == null) { myClassList = new ArrayList(); multiMap.put( (double) 0,myClassList); } myClassList.add("Value Duplicate"); for (Map.Entry entry : multiMap.entrySet()) { System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue()); }