如何解决检查 HashSet<int[]>
如何检查数组是否存在于 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
解决方法
使用数组
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
不认为包含相同顺序的相同数字的数组相等。一个数组只被认为等于它自己。因此,我们需要对集合进行线性搜索,以找到包含相同数字的数组(如果有)。我为此使用了流管道。您也可以使用循环。
更快:使用列表
要利用 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
)。不确定是否值得
现在添加所有可能的解决方案(也许还有更多?)。 :)
您可以使用 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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。