在Set中存储数组并避免重复

时间:2011-09-20 15:55:53

标签: java arrays generics hash set

HashSet<String[]> boog = new HashSet<String[]>();
boog.add(new String[]{"a", "b", "c"});
boog.add(new String[]{"a", "b", "c"});
boog.add(new String[]{"a", "b", "d"});

结果

[a, b, c]
[a, b, d]
[a, b, c]

其中[a,b,c]重复,因此散列函数未按预期工作。我将如何重写String数组的Hash方法。或者就此而言,通用数组?有没有更好的方法来完成我想要做的事情?

5 个答案:

答案 0 :(得分:32)

你做不到。数组使用默认的基于身份的Object.hashCode()实现,你无法覆盖它。不要在ArshMap / HashSet中使用Arrays作为键!

改为使用一组列表。

答案 1 :(得分:24)

“更好的方式”是使用集合。使用List代替String[]

Set<List<String>> boog = //...
boog.add(Arrays.asList("a", "b", "c"));
boog.add(Arrays.asList("a", "b", "c"));
boog.add(Arrays.asList("a", "b", "d"));

System.out.println(boog.size()); // 2

修改

如果您绝对需要使用数组作为键,则可以围绕每个键构建一个透明包装并将其放在地图中。有些图书馆会帮助您。例如,以下是使用Trove进行Set<String[]>的方法:

Set<String[]> boog = new TCustomHashSet<String[]>(new ArrayHashingStrategy());

boog.add(new String[]{"a", "b", "c"});
boog.add(new String[]{"a", "b", "c"});
boog.add(new String[]{"a", "b", "d"});

System.out.println(boog.size()); // 2

//...
public class ArrayHashingStrategy extends HashingStrategy<Object[]> {

   public int computeHashCode(Object[] array) {
      return Arrays.hashCode(array);
   }

   public boolean equals(Object[] arr1, Object[] arr2) {
      return Arrays.equals(arr1, arr2);
   }
}        

答案 2 :(得分:4)

hashCode()数组使用默认实现,但没有考虑元素,也无法更改。

您可以改为使用List,并根据其元素的哈希码计算hashCode()ArrayList(与大多数实现一样)使用此类函数。


或者(但不太可取,除非你被迫以某种方式使用数组),你可以使用“特殊”HashSet而不是调用key.hashCode()调用Arrays.hashCode(array)。要实现该扩展HashMap,然后使用Collections.newSetFromMap(map)

答案 3 :(得分:1)

您实际上正在使用默认的hashCode方法为所有不同的数组返回不同的值!

解决此问题的最佳方法是使用Collection(例如ListSet)或定义自己的包装类,例如:

public class StringArray {
    public String[] stringArray;

    [...] // constructors and methods

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        for(String string : stringArray){
            result = prime * result + ((string == null) ? 0 : string.hashCode());
        }
    }
}

此类实际上使用与hashCode几乎相同的List方法。

您现在处理:

HashSet<StringArray> boog = new HashSet<StringArray>();

答案 4 :(得分:0)

实际上,你可以。您可以使用提供的TreeSet Comparator。 在你的情况下,它将是:

Set<String[]> boog = new TreeSet<>((o1, o2) -> {
    for (int i = 0; i < o1.length; i++){
        int cmp = o1[i].compareTo(o2[i]);
        if (cmp != 0) {
            return cmp;
        }
    }
    return o1.length - o2.length;
});

在引擎盖下,它看起来像字母排序的树。