我能在HashMap中使用HashSet作为键吗?如果不行,请提供一个替代方案。

5

编辑:已经更好地解释了问题。

我有一个哈希映射表,想要存储一起出现的单词集合(键)和它们在哪些行中出现过(值)。这是我想出的结构:

HashMap<HashSet<String>, HashSet<Integer>> hm= ...

对于输入:

  1. 芒果,香蕉,苹果

  2. 苹果,香蕉

  3. 桃子,海象

  4. 海象,桃子

我逐行阅读,从每行中的单词组合创建新的临时键(尚未插入到哈希表中的哈希集)。 每个临时键都是行中一部分单词的哈希集。 如果一个临时键已经存在于我的哈希表中,我会进行检查,这可以通过

if(hashmap.containsKey(hashset))

我会将新行添加到该键的相应值中,如果没有,则在哈希映射表中创建一个新条目并进行维护。

我从未更改现有的键。我只更新它们在哈希映射表中对应的值。

读取完文件后,我的哈希映射表应该类似于:

[apple, banana]=[1,2]

[peach, walrus]=[3,4]

...

问题在于

if(hashmap.containsKey(hashset))

代码片段并不总是能够检测到已存在的键。为什么会这样?这种结构不被允许吗?

谢谢


第五行也会被映射到“peach,walrus”吗?那么“mango”呢? - Thomas
@pcalcao 是的,它的行为很奇怪。有时它会检测到集合存在,有时则不会。我只想验证 HashMap 是否可以将 HashSet 作为键处理。 - student101
@Thomas,抱歉,打错字了。已经删除了。 - student101
你可以让它为你工作。 - ring bearer
如果你想要进行一对一的键值映射,那么这绝对是一个坏主意。因为在集合中无法保证顺序。例如,如果你计划将苹果映射到1,香蕉映射到2,那么这种数据结构是行不通的。 - Prasanna
3个回答

8
这应该可以工作,但你需要谨慎可变键的可变性。如果你改变了一个键的内容,它的哈希码将会改变,你的映射表将开始做出奇怪的事情。来自于Map的javadoc:
注意:当使用可变对象作为map键时必须小心。当一个对象的值在该对象作为map键时发生修改并影响到比较相等性的时候,map的行为是未指定的。这个禁止规则的一个特殊情况是不允许一个map包含自身作为一个键。虽然一个map包含自己作为一个值是允许的,但极度谨慎是建议的:对于这样的map,equals和hashCode方法已经不再被很好地定义。
为了避免这种情况,应该在创建时立即使用Collections.unmodifiableSet()将键进行包装,或直接使用Guava中的ImmutableSet

@matt 你好,我现在已经重新表述了问题。之前的解释不是很清楚。在任何时候我都没有更改键,我只更新哈希映射中指向的值。 - student101

4
您可以将 HashSet 作为 HashMap 的键,但是一旦这样做后,就不应再修改它,因为 HashSet.hashCode() 可能会改变,这样您将无法再找到该 HashSet。换句话说,如果您要这样做,请确保您的键是不可变的 HashSets(详见 这里Matt的答案)。
另一种选择是使用 MultiKeyMap 以及来自 commons collectionsMultiKey

我给他点赞,但他为什么要使用替代方案呢?他可以直接在HashSet中覆盖equalshashcode方法。 - Cratylus
@user384706:没有必要扩展HashSet...但是为什么不发表一个回答来说明你的意思呢? - Lukas Eder
1
好的,我发布了一些内容。也许我没有看到某些东西正确。 - Cratylus
@LukasEder 我不会改变键,只会改变值。在我编写的代码中,如果(hashmap.containskey(hashset))...并不能总是告诉我集合是否已经存在。仍在寻找错误... - student101
@Arjun:这个问题变得相当令人困惑了……我不确定你在做什么以及问题出在哪里。 - Lukas Eder
显示剩余6条评论

1
你所遇到的问题已经被@Lukas和@Matt很好地解释了。
我认为你可以通过使用继承或装饰器模式来创建一个Hashset,以一种独立于内容的方式覆盖equalshashCode,从而解决这个问题。

这样,你就可以避免为了解决特定问题而引入第三方jar包的依赖关系。


这是一个有趣的选项!不过从原帖的文本中很难判断它是否会产生想要的结果... - Lukas Eder
我只是想知道是否有一些我没有看到的陷阱。在我看来,如果你不真正使用它们,最好避免引入额外的库。 - Cratylus

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