java 将数组存储在集中并避免重复

mwyxok5s  于 2023-01-15  发布在  Java
关注(0)|答案(6)|浏览(116)
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方法?或者,就此而言,一个泛型数组?有没有更好的方法来完成我试图做的事情?

zbdgwd5y

zbdgwd5y1#

你不能。数组使用默认的基于身份的Object.hashCode()实现,而且你不能覆盖它。不要将数组用作HashMap / HashSet中的键!
请改用一组列表。

kwvwclae

kwvwclae2#

"更好的方法"是使用集合。使用List而不是String[]

// TreeSet and other comparison based sets will not work as ArrayList does not implement Comparable
Set<List<String>> boog = new HashSet<>();
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

编辑

如果你确实需要使用数组作为键,你可以为每个键构建一个透明的 Package 器,并将其放入Map中,有些库可以帮助你做到这一点,例如,下面是你如何使用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);
   }
}
b4wnujal

b4wnujal3#

数组的hashCode()使用默认的实现,它不考虑元素,你不能改变它。
您可以使用List来代替,其中hashCode()是基于其元素的散列码来计算的。ArrayList(与大多数实现一样)使用这样的函数。
或者(但不太可取,除非你被迫使用数组),你可以使用一个“特殊的”HashSet,其中调用Arrays.hashCode(array)而不是调用key.hashCode()

jtoj6r0c

jtoj6r0c4#

实际上,你可以使用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;
});

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

8gsdolmq

8gsdolmq5#

您实际上使用的是默认的hashCode方法,它为所有不同的数组返回不同的值!
解决此问题的最佳方法是使用Collection(如ListSet)或定义您自己的 Package 器类,如:

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>();
nr7wwzry

nr7wwzry6#

您可以使用TreeSet
TreeSet使用Comparable.compareTo()Comparator.compare()而不是hashCode()equals()来比较元素。它可以在构造函数中指定。

public static void main(String[] args) {
    Set<String[]> boog = new TreeSet<>(Arrays::compare);
    boog.add(new String[]{"a", "b", "c"});
    boog.add(new String[]{"a", "b", "c"});
    boog.add(new String[]{"a", "b", "d"});
    for (String[] e : boog)
        System.out.println(Arrays.toString(e));
}

输出:

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

Arrays::compare是按字典顺序比较数组的Comparator

相关问题