繁体   English   中英

在java中获得两个集合之间的对称差异的最佳方法是什么?

[英]What is the best way get the symmetric difference between two sets in java?

我想知道是否有一种快速/干净的方法来获得两组之间的对称差异?

我有:

Set<String> s1 = new HashSet<String>();
s1.add("a");
s1.add("b");
s1.add("c");

Set<String> s2 = new HashSet<String>();
s2.add("b");

我需要类似的东西:

Set<String> diff = Something.diff(s1, s2);
// diff would contain ["a", "c"]

只是为了澄清我需要对称差异。

您可以使用Google Guava库中的一些函数(这真的很棒,我强烈推荐它!):

Sets.difference(s1, s2);
Sets.symmetricDifference(s1, s2);

差异()对称差异()的Javadocs

symmetricDifference()完全符合您的要求,但difference()通常也很有帮助。

这两种方法都返回实时视图,但您可以例如在结果集上调用.immutableCopy()以获得不变的集。 如果您不需要视图,但需要一个可以修改的集合实例,请调用.copyInto(s3) 有关这些方法,请参阅SetView

你想要对称差异

public static <T> Set<T> diff(final Set<? extends T> s1, final Set<? extends T> s2) {
    Set<T> symmetricDiff = new HashSet<T>(s1);
    symmetricDiff.addAll(s2);
    Set<T> tmp = new HashSet<T>(s1);
    tmp.retainAll(s2);
    symmetricDiff.removeAll(tmp);
    return symmetricDiff;
}

如果你想要一个库, Apache Commons CollectionUtils

CollectionUtils.disjunction(s1, s2)

它返回一个非泛型Collection

番石榴集

Sets.symmetricDifference(s1, s2)

它返回一个不可修改的Set作为通用Sets.SetView

Guava 更现代一些,支持泛型,但其中任何一个都可以。

如果您可以使用Apache-Commons Collections ,那么您正在寻找CollectionUtils.disjunction(Collection a, Collection b) 它返回两个集合的对称差异。

如果不是,则将两个集合的交集 ( retainAll ) 减去 ( removeAll ) 到两个集合的并集 ( addAll ):

Set<String> intersection = new HashSet<String>(set1);
intersection.retainAll(set2);

Set<String> difference = new HashSet<String>();
difference.addAll(set1);
difference.addAll(set2);
difference.removeAll(intersection);

循环遍历一组并进行比较。

循环遍历其中一组只需O(n) 考虑这个代码:

for (String key: oldSet) {
    if (newSet.contains(key))
        newSet.remove(key);
    else
        newSet.add(key);
}

并且newSet现在将只包含来自两个集合的唯一条目。 它很快,因为您只需要遍历其中一个集合中的元素,并且除非您明确需要副本,否则不必创建集合。

public class Practice {
    public static void main(String[] args) {
        Set<Integer> set1 = new HashSet<Integer>();
        Set<Integer> set2 = new HashSet<Integer>();
        set1.add(1);
        set1.add(4);
        set1.add(7);
        set1.add(9);

        set2.add(2);
        set2.add(4);
        set2.add(5);
        set2.add(6);
        set2.add(7);

        symmetricSetDifference(set1, set2);
    }

    public static void symmetricSetDifference(Set<Integer>set1, Set<Integer>set2){
        //creating a new set
        Set<Integer> newSet = new HashSet<Integer>(set1);
        newSet.removeAll(set2);
        set2.removeAll(set1);
        newSet.addAll(set2);
        System.out.println(newSet);
    }

}

Java 8 解决方案

我们可以在某些类SetUtils (say)编写两个实用程序方法(对于 java 8 和之前的),如下所示:

public static <T> Set<T> symmetricDifferenceJava8(final Set<T> setOne, final Set<T> setTwo) {
    Set<T> result = new HashSet<>(setOne);
    setTwo.stream().filter(not(resultSet::add)).forEach(resultSet::remove);
    return result;
}

public static <T> Set<T> symmetricDifference(final Set<T> setOne, final Set<T> setTwo) {
    Set<T> result = new HashSet<T>(setOne);
    for (T element : setTwo) {
        if (!result.add(element)) {
            result.remove(element);
        }
    }
    return result;
}

public static <T> Predicate<T> not(Predicate<T> t) {
    return t.negate();
}

如果元素已经存在,则方法add返回 false 并且方法 negate 用于否定谓词。

爪哇 11

我们在 Java 11 中有一个Predicate#not谓词方法,可以将它用作:

public static <T> Set<T> symmetricDifferenceJava11(final Set<T> setOne, final Set<T> setTwo) {
    Set<T> result = new HashSet<>(setOne);
    setTwo.stream().filter(Predicate.not(resultSet::add)).forEach(resultSet::remove);
    return result;
}
public class Practice {
    public static void main(String[] args) {
        Set<Integer> set1 = new HashSet<Integer>();
        Set<Integer> set2 = new HashSet<Integer>();
        set1.add(1);
        set1.add(4);
        set1.add(7);
        set1.add(9);

        set2.add(2);
        set2.add(4);
        set2.add(5);
        set2.add(6);
        set2.add(7);

        symmetricSetDifference(set1, set2);
    }

    public static void symmetricSetDifference(Set<Integer>set1, Set<Integer>set2){
        //creating a new set
        Set<Integer> newSet = new HashSet<Integer>(set1);
        newSet.removeAll(set2);
        set2.removeAll(set1);
        newSet.addAll(set2);
        System.out.println(newSet);
    }

如果ab是集合

a - b

a中不在b

>>> a = {1,2,3}
>>> b = {1,4,5}
>>> 
>>> a - b
{2, 3}
>>> b - a
{4, 5}

a.symmetric_difference(b)是恰好在一个集合中的所有元素,例如a - bb - a

>>> a.symmetric_difference(b)
{2, 3, 4, 5}
>>> (a - b).union(b - a)
{2, 3, 4, 5}

来自 io.datakernel.common.collection

public static <T> Set<T> difference(Set<? extends T> a, Set<? extends T> b) {
    return a.stream().filter(t -> !b.contains(t)).collect(toSet());
}

我想知道是否有一种快速/干净的方法来获得两组之间的对称差异?

我有:

Set<String> s1 = new HashSet<String>();
s1.add("a");
s1.add("b");
s1.add("c");

Set<String> s2 = new HashSet<String>();
s2.add("b");

我需要类似的东西:

Set<String> diff = Something.diff(s1, s2);
// diff would contain ["a", "c"]

只是为了澄清一下,我需要对称的区别。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM