使用数组
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 的快速查找。如 cmets 中所述,这是不可能的,因为数组的 equals 和 hashCode 不认为包含相同顺序的相同数字的数组是相等的。一个数组只被认为等于它自己。因此,我们需要对集合进行线性搜索,以找到包含相同数字的数组(如果有的话)。我正在为此使用流管道。您也可以使用循环。
更快:使用列表
要利用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()的时间效率。
更多选项(谢谢,蓬松)
作为 cmets 中的蓬松笔记,还有更多选择,您可能想自己研究一些。我在这里引用 cmets:
此外,如果我没记错的话,可能有两种基于密钥的解决方案:
喜欢
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 正确)。不确定是否值得
现在添加所有可能的解决方案(也许还有更多?)。 :)