为什么Java Set上的remove()方法不起作用



我有以下代码:

Set<Set<Integer>> groups = new HashSet<>();
for (int[] edge : edges) {
Set<Integer> match1 = null;
Set<Integer> match2 = null;
for(Set<Integer> group : groups) {
if(group.contains(edge[0])) match1 = group;
if(group.contains(edge[1])) match2 = group;
}
if(match1 != null && match1 == match2) {
result = edge;
}else if(match1 != null && match2 != null && match1 != match2) {
match1.addAll(match2);
groups.remove(match2);     <---- This does not remove match2 from set
}else{
Set<Integer> newGroup = new HashSet<>();
newGroup.add(edge[0]);
newGroup.add(edge[1]);
groups.add(newGroup);
}

.........
}

groups是一组整数。

但是,groups.remove(match2(方法不会从组中删除整数集。

这里发生了什么?

引用Set接口文档:

注意:如果可变对象用作集合元素,则必须格外小心。当对象是集合中的元素时,如果对象的值以影响相等比较的方式更改,则不指定集合的行为。这种禁止的一个特殊情况是,不允许集合将自己作为元素包含。

match1仍在外部Set中时,使用addAll()调用对其进行变异,这违反了此规则。这种突变会导致哈希代码在外部Set不知情的情况下发生更改,因此内部Set现在位于错误的哈希桶中,当您试图在后续迭代中删除它时,无法找到它。

作为一种变通方法,您可以删除它,然后调用addAll(),然后再次添加它。在内部,这将导致它被放置在新哈希代码的正确哈希桶中。


顺便说一句,看起来你正在实现一个连接组件检测算法。使用不相交的集合林数据结构可以更有效地执行此操作。在如何将每个集合存储在不相交的集合林中,有一些很好的伪代码。

最新更新