我想知道是否有快速/干净的方法来获得两组之间的对称差异?
我有:
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"]
只是为了澄清我需要对称差异。
答案 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)
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
。
番石榴更现代,支持仿制药,但其中任何一种都可以使用。
答案 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)
我们可以在某个类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中,我们有一个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);
}
如果设置了a
和b
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 - b
和b - 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);
应该工作。