I'm wondering if there is a quick/clean way to get the symmetric difference between two sets ?
我想知道是否有快速/干净的方法来获得两组之间的对称差异?
I have:
Set<String> s1 = new HashSet<String>();
s1.add("a");
s1.add("b");
s1.add("c");
Set<String> s2 = new HashSet<String>();
s2.add("b");
I need something like:
我需要这样的东西:
Set<String> diff = Something.diff(s1, s2);
// diff would contain ["a", "c"]
Just to clarify I need the symmetric difference.
只是为了澄清我需要对称差异。
7 个解决方案
#1
40
You can use some functions from the Google Guava library (which is really great, I strongly recommend it!):
您可以使用Google Guava库中的一些功能(这非常棒,我强烈推荐它!):
Sets.difference(s1, s2);
Sets.symmetricDifference(s1, s2);
Javadocs for difference() and symmetricDifference()
差异()和symmetricDifference()的Javadocs
symmetricDifference()
does exactly what you are asking for, but difference()
is also often helpful.
symmetricDifference()完全符合您的要求,但difference()通常也很有帮助。
Both methods return a live view, but you can for example call .immutableCopy()
on the resulting set to get a non-changing set. If you don't want a view, but need a set instance you can modify, call .copyInto(s3)
. See SetView for these methods.
两种方法都返回实时视图,但您可以在结果集上调用.immutableCopy()以获取不变的集合。如果您不想要视图,但需要一个可以修改的set实例,请调用.copyInto(s3)。有关这些方法,请参阅SetView。
#2
31
You want the 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;
}
If you want a library, Apache Commons CollectionUtils has
如果你想要一个库,Apache Commons CollectionUtils就有了
CollectionUtils.disjunction(s1, s2)
which returns a non-generic Collection
.
它返回一个非泛型的Collection。
and Guava Sets has
和番石榴套装有
Sets.symmetricDifference(s1, s2)
which returns an unmodifiable Set
as a generic Sets.SetView
.
它返回一个不可修改的Set作为泛型Sets.SetView。
Guava is a bit more modern, supporting generics, but either of these will work.
番石榴更现代,支持仿制药,但其中任何一种都可行。
#3
4
If you can use Apache-Commons Collections, you are looking for CollectionUtils.disjunction(Collection a, Collection b)
. It returns the symmetric difference of both Collections.
如果您可以使用Apache-Commons Collections,那么您正在寻找CollectionUtils.disjunction(Collection a,Collection b)。它返回两个集合的对称差异。
If not, substract (removeAll
) the intersection (retainAll
) of both sets to the union of both (addAll
):
如果没有,则将两个集合的交集(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);
#4
4
Loop through one set and compare.
循环一组并进行比较。
It's only O(n)
to loop through one of the sets. Consider this code:
只有O(n)才能遍历其中一组。考虑以下代码:
for (String key: oldSet) {
if (newSet.contains(key))
newSet.remove(key);
else
newSet.add(key);
}
And the newSet
will now contain only the unique entries from both sets. It's fast, because you only need to loop through the elements in one of the sets and you don't have to create sets unless you explicitly need a copy.
而newSet现在只包含两个集合中的唯一条目。它很快,因为您只需要遍历其中一个集合中的元素,除非明确需要副本,否则不必创建集合。
#5
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);
}
}
#6
0
Java 8 Solution
We can write two utility methods (for java 8 and prior) in some class SetUtils (say)
as:
我们可以在一些类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();
}
The method add
returns false if element already exists and method negate is used to negate the predicate.
如果元素已经存在,则方法add返回false,并且使用方法negate来否定谓词。
Java 11
We have a Predicate#not method for predicate in Java 11 and can use it as:
我们在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;
}
#7
-4
s1.addAll(s2);
s1.removeAll(s2);
Should work.
#1
40
You can use some functions from the Google Guava library (which is really great, I strongly recommend it!):
您可以使用Google Guava库中的一些功能(这非常棒,我强烈推荐它!):
Sets.difference(s1, s2);
Sets.symmetricDifference(s1, s2);
Javadocs for difference() and symmetricDifference()
差异()和symmetricDifference()的Javadocs
symmetricDifference()
does exactly what you are asking for, but difference()
is also often helpful.
symmetricDifference()完全符合您的要求,但difference()通常也很有帮助。
Both methods return a live view, but you can for example call .immutableCopy()
on the resulting set to get a non-changing set. If you don't want a view, but need a set instance you can modify, call .copyInto(s3)
. See SetView for these methods.
两种方法都返回实时视图,但您可以在结果集上调用.immutableCopy()以获取不变的集合。如果您不想要视图,但需要一个可以修改的set实例,请调用.copyInto(s3)。有关这些方法,请参阅SetView。
#2
31
You want the 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;
}
If you want a library, Apache Commons CollectionUtils has
如果你想要一个库,Apache Commons CollectionUtils就有了
CollectionUtils.disjunction(s1, s2)
which returns a non-generic Collection
.
它返回一个非泛型的Collection。
and Guava Sets has
和番石榴套装有
Sets.symmetricDifference(s1, s2)
which returns an unmodifiable Set
as a generic Sets.SetView
.
它返回一个不可修改的Set作为泛型Sets.SetView。
Guava is a bit more modern, supporting generics, but either of these will work.
番石榴更现代,支持仿制药,但其中任何一种都可行。
#3
4
If you can use Apache-Commons Collections, you are looking for CollectionUtils.disjunction(Collection a, Collection b)
. It returns the symmetric difference of both Collections.
如果您可以使用Apache-Commons Collections,那么您正在寻找CollectionUtils.disjunction(Collection a,Collection b)。它返回两个集合的对称差异。
If not, substract (removeAll
) the intersection (retainAll
) of both sets to the union of both (addAll
):
如果没有,则将两个集合的交集(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);
#4
4
Loop through one set and compare.
循环一组并进行比较。
It's only O(n)
to loop through one of the sets. Consider this code:
只有O(n)才能遍历其中一组。考虑以下代码:
for (String key: oldSet) {
if (newSet.contains(key))
newSet.remove(key);
else
newSet.add(key);
}
And the newSet
will now contain only the unique entries from both sets. It's fast, because you only need to loop through the elements in one of the sets and you don't have to create sets unless you explicitly need a copy.
而newSet现在只包含两个集合中的唯一条目。它很快,因为您只需要遍历其中一个集合中的元素,除非明确需要副本,否则不必创建集合。
#5
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);
}
}
#6
0
Java 8 Solution
We can write two utility methods (for java 8 and prior) in some class SetUtils (say)
as:
我们可以在一些类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();
}
The method add
returns false if element already exists and method negate is used to negate the predicate.
如果元素已经存在,则方法add返回false,并且使用方法negate来否定谓词。
Java 11
We have a Predicate#not method for predicate in Java 11 and can use it as:
我们在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;
}
#7
-4
s1.addAll(s2);
s1.removeAll(s2);
Should work.