在Java中比较两个集合的最快方法是什么?
我试图优化一段比较列表元素的代码 例如在Java中比较两个集合的最快方法是什么?,java,performance,set,Java,Performance,Set,我试图优化一段比较列表元素的代码 例如 public void compare(设置第一组,设置第二组){ 用于(记录firstRecord:firstSet){ 用于(记录第二个记录:第二组){ //比较逻辑 } } } 请考虑到成套记录的数量将很高 谢谢 谢哈尔 firstSet.equals(secondSet) 这真的取决于你想在比较逻辑中做什么。。。如果在一个集合中发现一个元素而不是在另一个集合中,会发生什么?您的方法有一个void返回类型,因此我假设您将在该方法中执行必要的工作
public void compare(设置第一组,设置第二组){
用于(记录firstRecord:firstSet){
用于(记录第二个记录:第二组){
//比较逻辑
}
}
}
请考虑到成套记录的数量将很高
谢谢
谢哈尔
firstSet.equals(secondSet)
这真的取决于你想在比较逻辑中做什么。。。如果在一个集合中发现一个元素而不是在另一个集合中,会发生什么?您的方法有一个void
返回类型,因此我假设您将在该方法中执行必要的工作
更细粒度的控制(如果需要):
if (!firstSet.containsAll(secondSet)) {
// do something if needs be
}
if (!secondSet.containsAll(firstSet)) {
// do something if needs be
}
如果需要获取一个集合中的元素而不是另一个集合中的元素。
编辑:
set.removeAll(otherSet)
返回布尔值,而不是集合。要使用removeAll(),必须先复制集合,然后再使用它
Set one = new HashSet<>(firstSet);
Set two = new HashSet<>(secondSet);
one.removeAll(secondSet);
two.removeAll(firstSet);
Set one=新哈希集(firstSet);
Set二=新哈希集(secondSet);
一、拆除所有(第二套);
二、拆除所有(第一套);
如果one
和two
的内容都是空的,那么您就知道这两个集合是相等的。如果不是,那么你就得到了使集合不相等的元素
您提到记录的数量可能很高。如果底层实现是一个
HashSet
,那么每个记录的获取都是在O(1)
时间内完成的,因此您不会得到比这更好的结果TreeSet
是O(log n)
如果您只是想知道这些集合是否相等,则AbstractSet
上的equals
方法大致实现如下:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return containsAll(c);
}
注意它如何优化常见情况,其中:
- 这两个对象是相同的
- 另一个对象根本不是集合,并且
- 这两套的尺寸不同
containsAll(…)
在另一个集合中找到不在该集合中的元素时,将返回false
。但如果两个集合中都存在所有元素,则需要测试所有元素
因此,当两个集合相等但对象不同时,性能最差。该成本通常为O(N)
或O(NlogN)
,具体取决于this.containsAll(c)
的实现
如果集合比较大,并且只在元素的极小百分比上存在差异,则接近最坏情况下的性能
更新 如果您愿意在自定义集实现上投入时间,那么有一种方法可以改进“几乎相同”的情况 其思想是,您需要预先计算并缓存整个集合的哈希值,以便可以在
O(1)
中获得集合的当前哈希值。然后,您可以将这两个集合的哈希代码作为加速进行比较
如何实现这样的哈希代码?如果设置的哈希代码是:
- 空集合为零,并且
- 非空集的所有元素哈希码的异或
O(N)
比较
你可以把这个想法再进一步。。。至少在理论上是这样 警告-这是高度推测性的。一个“思想实验”,如果你喜欢的话 假设set元素类有一个方法返回元素的加密校验和。现在,通过对元素返回的校验和进行XOR运算来实现集合的校验和 这给我们买了什么 好的,如果我们假设没有任何暗箱操作,那么任意两个不相等集合元素具有相同N位校验和的概率是2-N。并且两个不相等集合具有相同N位校验和的概率也是2-N。因此我的想法是,您可以实现
equals
,如下所示:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return checksums.equals(c.checksums);
}
在上述假设下,这只会在2-N时间内给你一次错误的答案。如果使N足够大(例如512位),则错误答案的概率可以忽略不计(例如大约10-150)
缺点是,计算元素的加密校验和非常昂贵,尤其是当比特数增加时。所以你真的需要一个有效的机制来记忆校验和。这可能是个问题
另一个缺点是,无论错误概率有多小,非零的错误概率都是不可接受的。(但如果是这样的话……你如何处理宇宙射线翻转一个关键位的情况?或者如果它在冗余系统的两个实例中同时翻转同一位的情况?公共布尔等于(对象o){
如果(o==这个)
返回true;
如果(!(集合的o实例))
返回false;
设置a=此;
设置b=o;
设置差异_a_b=新哈希集(a);
差异a_b.移除所有(b);
如果(差值a_b.isEmpty()==false)返回false;
设置差异_b_a=新哈希集(b);
差异消除了所有(a);
如果(差分为空()==false)返回false;
返回true;
}
番石榴中有一种方法可以帮助您:
public static <E> boolean equals(Set<? extends E> set1, Set<? extends E> set2){
return Sets.symmetricDifference(set1,set2).isEmpty();
}
publicstaticbooleanequals(Set对于以下非常特殊的情况,有一个O(N)解决方案:
- 这两个集合都已排序
- 两个都按相同顺序排序
下面的代码假设这两组数据都基于可比较的记录
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Set<String> a = this;
Set<String> b = o;
Set<String> thedifference_a_b = new HashSet<String>(a);
thedifference_a_b.removeAll(b);
if(thedifference_a_b.isEmpty() == false) return false;
Set<String> thedifference_b_a = new HashSet<String>(b);
thedifference_b_a.removeAll(a);
if(thedifference_b_a.isEmpty() == false) return false;
return true;
}
public static <E> boolean equals(Set<? extends E> set1, Set<? extends E> set2){
return Sets.symmetricDifference(set1,set2).isEmpty();
}
public class SortedSetComparitor <Foo extends Comparable<Foo>>
implements Comparator<SortedSet<Foo>> {
@Override
public int compare( SortedSet<Foo> arg0, SortedSet<Foo> arg1 ) {
Iterator<Foo> otherRecords = arg1.iterator();
for (Foo thisRecord : arg0) {
// Shorter sets sort first.
if (!otherRecords.hasNext()) return 1;
int comparison = thisRecord.compareTo(otherRecords.next());
if (comparison != 0) return comparison;
}
// Shorter sets sort first
if (otherRecords.hasNext()) return -1;
else return 0;
}
}
HashMap<Integer,Record> hm = new HashMap<Integer,Record>(secondSet.size());
int i = 0;
for(Record secondRecord : secondSet){
hm.put(i,secondRecord);
i++;
}
for(Record firstRecord : firstSet){
for(int i=0; i<secondSet.size(); i++){
//use hm for comparison
}
}
SetView<Record> added = Sets.difference(secondSet, firstSet);
SetView<Record> removed = Sets.difference(firstSet, secondSet);
Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Set<String> set2 = new HashSet<>();
set2.addAll(Arrays.asList("hanks","leo","bale"));
Predicate<Set> pred = set::equals;
boolean result = pred.test(set2);
System.out.println(result); // true
public static boolean equals(Set<?> set1, Set<?> set2){
if(set1 == null || set2 ==null){
return false;
}
if(set1.size() != set2.size()){
return false;
}
return set1.containsAll(set2);
}
public static boolean equals(Set<?> set1, Set<?> set2){
return set1 != null
&& set2 != null
&& set1.size() == set2.size()
&& set1.containsAll(set2);
}