在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)
中获得集合的当前哈希值。然后,您可以将这两个集合的哈希代码作为加速进行比较

如何实现这样的哈希代码?如果设置的哈希代码是:

  • 空集合为零,并且
  • 非空集的所有元素哈希码的异或
然后,您可以在每次添加或删除元素时廉价地更新集合的缓存哈希代码。在这两种情况下,只需将元素的hashcode与当前设置的hashcode进行异或

当然,这假设元素hashcode是稳定的,而元素是集合的成员。它还假设元素类hashcode函数提供了良好的扩展。这是因为,当两组hashcode相同时,您仍然必须返回到所有元素的
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);
}