在java中获取两组之间的对称差异的最佳方法是什么?

时间:2011-11-09 11:49:15

标签: java collections set

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

我有:

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"]

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

9 个答案:

答案 0 :(得分:41)

您可以使用Google Guava库中的一些功能(这非常棒,我强烈推荐它!):

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

difference()symmetricDifference()

的Javadoc

symmetricDifference()完全what you are asking for,但difference()也常有帮助。

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

答案 1 :(得分:32)

您需要symmetric difference

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

Guava Sets

Sets.symmetricDifference(s1, s2)

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

番石榴更现代,支持仿制药,但其中任何一种都可以使用。

答案 2 :(得分:5)

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

如果没有,则将两个集合的交集(removeAll)减去(retainAll)两者的联合(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);

答案 3 :(得分:4)

循环播放一组并进行比较。

只有O(n)才能遍历其中一组。请考虑以下代码:

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

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

答案 4 :(得分:1)

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);
    }

}

答案 5 :(得分:0)

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();
}

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

Java 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;
}

答案 6 :(得分:0)

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}

答案 7 :(得分:0)

来自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());
}

答案 8 :(得分:-4)

s1.addAll(s2);
s1.removeAll(s2);

应该工作。