将具有相同值的数组添加到 HashSet 会导致重复项 [英] Adding arrays with same values to HashSet results in duplicate items

查看:35
本文介绍了将具有相同值的数组添加到 HashSet 会导致重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一组整数数组,如果我尝试这样做:

I'm trying to create a set of arrays of ints, the thing is that if I try to do:

HashSet<int[]> s = new HashSet<int[]>();
int a1[] = {1,2,3};
int a2[] = {1,2,3};
s.add(a1);
s.add(a2)
System.out.println(s.size());

那么s有两个对象,但应该只有一个.注意:如果是HashSet<则无所谓整数[]>.它只是不起作用.

Then s has two objects, but there should be only one. Note: it doesn't matter if it is HashSet< Integer[]>. It just doesn't work.

现在,如果我尝试使用 ArrayList<Integer>,类似于:

Now If I try to do this with an ArrayList< Integer>, something like:

HashSet<ArrayList<Integer>> s = new HashSet<ArrayList<Integer>>();
ArrayList<Integer> a1 = new ArrayList<Integer>();
ArrayList<Integer> a2 = new ArrayList<Integer>();
a1.add(1);
a1.add(2);
a1.add(3);

a2.add(1);
a2.add(2);
a2.add(3);

s.add(a1);
s.add(a2)
System.out.println(s.size());

那么 s 有一个对象.

Then s has one object.

我想了一种方法来避免第一个代码中的错误,并将每个数组的哈希码存储在一个哈希集中,如下所示:

I though a way to avoid the error in the first code and was storing hashcodes of each array in a hashset as follows:

int a1[] = {0,10083,10084,1,0,1,10083,0,0,0,0};
int a2[] = {1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0,2112};
HashSet<Integer> s= new HashSet<Integer>();//hashcodes of each array
s.add(Arrays.hashCode(a1));
s.add(Arrays.hashCode(a2));
System.out.println(Arrays.hashCode(a1));
System.out.println(Arrays.hashCode(a2));
System.out.println(s.size());

它适用于第一种情况(1,2,3),但在发生碰撞的情况下它不起作用,所以我必须管理碰撞.所以,我认为我正在做的是自己实现一个HashSet.

It works for the first case(1,2,3) but in cases where there are collisions it doesn't work, so I would have to manage collisions. So, I think that what I am doing is implementing a HashSet by myself.

使用 HashSet<数组列表<整数>>它完美地工作.我想在这种情况下 java 会管理冲突.

With HashSet< ArrayList< Integer>> it works perfectly. I suppose that java manage collisions in that case.

我的问题是为什么java不允许管理HashSet<int[]> 或 HashSet 如果生成的哈希码与 ArrayList<;Integer> 和数组的hashcode 可以通过调用Arrays.hashCode(...) 来计算.

My question is why java does not allow to manage a HashSet< int[]> or HashSet< Integer[]> if hashcodes generated are the same as in ArrayList< Integer> and hashcodes of arrays can be calculated simply by calling Arrays.hashCode(...).

最后,如果我想做一个 HashSet<int[]>(or HashSet) 我必须自己实现它?或者有更好的方法吗?

And finally, if I want to do a HashSet< int[]>(or HashSet< Integer[]>) I would have to implement it by myself? Or there is a better way to do it?

谢谢.

更新:好吧,我想我终于找到了一个完整的答案.正如@ZiyaoWei 和@user1676075 评论的那样,它不起作用,因为 equals 返回 false 并且哈希码不同.但是,为什么 java 不覆盖这个方法(使用 Arrays.equals(), Arrays.hashCode())所以可以做一些类似 HashSet< 的事情.内部[]>?答案是因为数组是一个可变对象,根据哈希码的一般约定,哈希码不能依赖于可变值(数组的每个元素都是一个可变值).可变对象和哈希码

UPDATE: Ok, finally I think I have came to a complete answer. As @ZiyaoWei and @user1676075 commented it doesn't work because equals returns false and hashcodes are differents. But, why java does not override this methods(with Arrays.equals(), Arrays.hashCode()) so one can do something like HashSet< int[]>? The answer is because an array is a mutable object, and hashcode can not depend on mutable values(each element of array is a mutable value) according to the general contract of hashcode. Mutable objects and hashCode

这里很好地解释了在 hashCode 中使用可变字段 http:///blog.mgm-tp.com/2012/03/hashset-java-puzzler/ 和哈希图中的可变键 可变哈希映射键是一种危险的做法吗?

Here nice explanations of using mutable fields in hashCode http://blog.mgm-tp.com/2012/03/hashset-java-puzzler/ and mutable keys in hashmaps Are mutable hashmap keys a dangerous practice?

我的回答是,如果您想使用 HashSet<int[]> 您必须创建一个具有数组的类,如果您希望该 hashcode 和 equals 依赖于值,请使用 Arrays.equals() 和 Arrays.hashCode() 覆盖方法 equals() 和 hashCode().如果您不想违反合同,只需将数组设为 final.

My answer is, if you want to use a HashSet< int[]> you have to create a class that has an array and if you want that hashcode and equals to depend on values, override methods equals() and hashCode() with Arrays.equals() and Arrays.hashCode(). If you don't want to violate the contract just make the array final.

谢谢大家!

推荐答案

与最终碰撞无关:

a1.equals(a2) == false

由于它们不相等,Set 会将它们视为不同.

Since they are not equal, a Set will treat them as different.

注意Java中的Array不会覆盖Object中的equals方法.

Note Array in Java does not override the equals method from Object.

并且由于Set中的add被定义为

更正式地,如果集合不包含元素 e2 使得 (e==null ? e2==null : e.equals(e2)) ,则将指定的元素 e 添加到该集合中

More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2))

似乎不可能在不违反某些合同的情况下正确实现可能满足您要求的 Set(将元素与 Arrays.equals 进行比较).

is seems to be impossible to properly implement a Set that might meet your requirement (compare elements with Arrays.equals) without violating some contracts.

这篇关于将具有相同值的数组添加到 HashSet 会导致重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆