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

在java中,获得两个集合之间对称差异的最佳方法是什么?,java,collections,set,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 s1=new HashSet(); s1.添加(“a”); s1.添加(“b”); s1.添加(“c”)

我想知道是否有一种快速/干净的方法可以得到两个集合之间的对称差

我有:

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 s1=new HashSet();
s1.添加(“a”);
s1.添加(“b”);
s1.添加(“c”);
Set s2=新的HashSet();
s2.添加(“b”);
我需要像这样的东西:

Set<String> diff = Something.diff(s1, s2);
// diff would contain ["a", "c"]
Set diff=Something.diff(s1,s2);
//差异将包含[“a”、“c”]


我只想澄清一下,我需要对称的区别。

您可以使用库中的一些函数(非常好,我强烈推荐!)

用于和的Javadocs

symmetricDifference()
确实如此,但是
difference()
通常也很有用

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

s1.addAll(s2);
s1.removeAll(s2);
应该有用。

如果您可以使用,您正在寻找。它返回两个集合的对称差

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

Set intersection=新哈希集(set1);
交叉口。保留(set2);
Set difference=新的HashSet();
差异。添加全部(set1);
差异。添加全部(set2);
差异。移除所有(交叉点);
您想要的是

它返回一个非泛型的
集合

而且

它返回一个不可修改的
集合
,作为通用的
集合。SetView


番石榴有点现代,支持仿制药,但这两种都可以用。

在一个集合中循环并比较。

只有
O(n)
才能循环通过其中一个集合。考虑这个代码:

for (String key: oldSet) {
    if (newSet.contains(key))
        newSet.remove(key);
    else
        newSet.add(key);
}
newSet
现在将只包含两个集合中唯一的条目。这很快,因为您只需要循环遍历其中一个集合中的元素,并且除非您明确需要一个副本,否则不必创建集合。

public class Practice{
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);
    }
公共静态void main(字符串[]args){ Set set1=新的HashSet(); Set set2=新的HashSet(); set1.添加(1); set1.添加(4); set1.添加(7); set1.添加(9); set2.添加(2); set2.添加(4); set2.添加(5); set2.添加(6); set2.添加(7); 对称性集差(set1,set2); } 公共静态void symmetricSetDifference(集合1、集合2){ //创建新集合 Set newSet=newhashset(set1); 新闻集删除全部(set2); set2.移除所有(set1); newSet.addAll(set2); System.out.println(新闻集); }
}

Java8解决方案 我们可以在某些类
SetUtils(比如)
中编写两个实用程序方法(适用于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();
}
所有东西都在
a
中,而不在
b

>>> a = {1,2,3}
>>> b = {1,4,5}
>>> 
>>> a - b
{2, 3}
>>> b - a
{4, 5}
a.symmetric\u difference(b)
是恰好在一个集合中的所有元素,例如
a-b
b-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());
}

publicstaticsetdifference(SetQuick&easy:您可以编写Set diff=newhashset(s1);diff.removeAll(s2);@polkageist:对于s1={“a”,“b”,“c”},s2={“b”,“d”}将失败。结果应该是{“a”,“c”,“d”}如果通过“difference”(cf.),OP意味着对称差,那么您是对的。然而,您可以通过(a-b)+(b-a)或(a+b)得到它-(A cap B)。我不知道用java实现这一点有什么更快的方法。java 8和java 11:谢谢,我实际上是在寻找一个可以为我实现这一点的库,因为这是我目前在支持泛型中所做的。对于S1={“A”,“B”,“c”},S2={“B”,“d”},这将失败。结果应该是{“A”,“c”,“d”}。这是一个不对称的差异。他想要对称的差异。刚刚阅读了javadoc for symetricDifference(),我有点担心这句话“如果set1和set2是基于不同等价关系的集(如HashSet、TreeSet和IdentityHashMap的键集都是这样),则结果是未定义的。”这听起来好像OP的情况(以及Sets.symmetricDifference()的情况)的结果是未定义的方法似乎没有那么有用。@Gus JavaDoc想说结果是未定义的,如果您对使用不同等价关系的两个不同集合使用该方法,例如,计算
HashSet
TreeSet
之间的差异可能会有问题。将该方法与两个
HashSet
s或两个
TreeSet
等都可以。@Gus此外,如果元素的
compareTo()
方法和
equals()
方法彼此一致(这是他们的文档强烈推荐的),那么将该方法与
HashSet
TreeSet
一起使用也可以。因此,只有在特殊情况下,该方法才能保证差分计算正确,在大多数实际情况下,该方法会很好地工作。我对该声明也有同样的担忧。感谢@PhilippWendler澄清这一点!尽管此代码可能会回答该问题,但提供了有关为什么和/或如何回答问题的其他上下文此操作将显著提高其长期价值。请您的答案添加一些解释。请注意,对于
HashSet
,此操作仅为
O(n)
,没有冲突。对于树集,所有三个操作
add(key)
都包含(key)
remove(key)
将需要搜索树一次,即额外的
O(n log n)
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);
    }
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();
}
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);
    }
a - b
>>> a = {1,2,3}
>>> b = {1,4,5}
>>> 
>>> a - b
{2, 3}
>>> b - a
{4, 5}
>>> a.symmetric_difference(b)
{2, 3, 4, 5}
>>> (a - b).union(b - a)
{2, 3, 4, 5}
public static <T> Set<T> difference(Set<? extends T> a, Set<? extends T> b) {
    return a.stream().filter(t -> !b.contains(t)).collect(toSet());
}