检查哈希集中是否存在数组< int[]>

lmyy7pcs  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(319)

如何检查数组中是否存在数组 HashSet ?
例如:

int[] a = new int[]{0, 0};

HashSet<int[]> set = new HashSet<>();
set.add(a);

然后:

int[] b = new int[]{0, 0};

set.contains(b); // ===> true
watbbzwu

watbbzwu1#

你可以用 TreeSet 而不是 HashSet 使用比较器比较两个数组的内容,而不是两个数组对象的哈希码。那你可以用 TreeSet.contains 方法如下:

int[] a = {0, 0};
int[] b = {0, 0};
int[] c = {0, 0};

HashSet<int[]> hashSet = new HashSet<>();
TreeSet<int[]> treeSet = new TreeSet<>(Arrays::compare);

hashSet.addAll(List.of(a, b, c));
treeSet.addAll(List.of(a, b));

System.out.println(hashSet.size()); // 3
System.out.println(treeSet.size()); // 1

System.out.println(treeSet.contains(a)); // true
System.out.println(treeSet.contains(b)); // true
System.out.println(treeSet.contains(c)); // true
tsm1rwdh

tsm1rwdh2#

使用数组

int[] a = new int[] { 0, 0 };
    HashSet<int[]> set = new HashSet<>();
    set.add(a);

    int[] b = new int[] { 0, 0 };

    boolean contains = set.stream().anyMatch(c -> Arrays.equals(c, b));

    System.out.println("Contains? " + contains);

输出:
包含?是的
它不会利用 HashSet 不过。正如评论中指出的,这是不可能的,因为 equals 以及 hashCode for数组不认为包含相同顺序的相同数字的数组相等。数组只被认为与自身相等。因此,我们需要对集合进行线性搜索,以找到包含相同数字的数组(如果有)。我用的是一条流管道。也可以使用循环。

更快:使用列表

利用 HashSet 可以使用列表而不是数组:

List<Integer> a = List.of(0, 0);
    HashSet<List<Integer>> set = new HashSet<>();
    set.add(a);

    List<Integer> b = List.of(0, 0);

    System.out.println("Contains? " + set.contains(b));

包含?是的
这个 List<Integer> 不过,这种方法有一个空间代价,因为它是存储的 Integer 对象而不是 int 基本体,通常占用更多空间。

节省空间和时间:开发自定义类

如果上述方法仍然不够有效(大多数情况下都是如此),您可以使用自己的类来计算数字:

public class IntArray {

    int[] elements;

    public IntArray(int... elements) {
        // Make a defensive copy to shield from subsequent modifications of the original array
        this.elements = Arrays.copyOf(elements, elements.length);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(elements);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IntArray other = (IntArray) obj;
        return Arrays.equals(elements, other.elements);
    }

}

这将允许:

IntArray a = new IntArray(0, 0);
    HashSet<IntArray> set = new HashSet<>();
    set.add(a);

    IntArray b = new IntArray(0, 0);

    System.out.println("Contains? " + set.contains(b));

包含?是的
现在我们有了原来的空间效率 int 阵列方法,近,和时间效率 hashCode() .

更多选择(谢谢,毛茸茸的)

作为评论中的模糊注解,还有更多的选择,您可能需要自己研究一些。我在这里引用评论:
另外,如果我没说错的话,可能有两种基于关键点的解决方案:类似于

public final class IntArrayKey {
    private final int[];
    ...
}

(遭受可能的阵列突变或防御性阵列克隆)或类似的情况

public final class Key<T> {
    private final Predicate<T> equals;
    private final IntSupplier hashCode;
    public static Key<int[]> of(final int[] array) {
        return new Key<>(that -> Arrays.equals(array, that), () -> Arrays.hashCode(array));
    }

保持通用性。
我能想到的另一个解决方案可能是使用fastutil或trove而不是 List<Integer> (例如。 IntList 它覆盖了 equals 以及 hashCode 正确地)。不确定是否值得现在添加所有可能的解决方案(也许还有更多?)

相关问题