得出两组之间的差异


161

因此,如果我有两套:

Set<Integer> test1 = new HashSet<Integer>();
test1.add(1);
test1.add(2);
test1.add(3);

Set<Integer> test2 = new HashSet<Integer>();
test2.add(1);
test2.add(2);
test2.add(3);
test2.add(4);
test2.add(5);

有没有一种方法可以比较它们,并且只返回一组4和5?



11
这不是精确的重复:对称差异和差异不相同。
西蒙·尼克森

如果test1包含6,答案是4,5,6吗?即您是否想要对称差异en.wikipedia.org/wiki/Symmetric_difference
Colin D

1
如果test1的含有6,我想答案还是4,5
大卫Tunnell

Answers:


197

试试这个

test2.removeAll(test1);

设置#removeAll

从该集合中删除所有包含在指定集合中的元素(可选操作)。如果指定的集合也是一个集合,则此操作将有效地修改此集合,以使其值为两个集合的非对称集合差异。


43
这将起作用,但是我认为将set操作(例如union,Difference)内置在Java中将是一个不错的功能。上面的解决方案将修改集合,在许多情况下,我们实际上并不需要这样。
Praveen Kumar 2014年

129
Java的,怎么还有胆量把这个数据结构Set时,它并没有定义unionintersection或者difference!!!
詹姆斯·纽曼

10
此解决方案并不完全正确。因为test1和test2的顺序有所不同。
Bojan Petkovic

1
test1.removeAll(test2);返回与相同的结果test2.removeAll(test1);吗?
datv

3
@datv结果将有所不同。test1.removeAll(test2)是一个空集。test2.removeAll(test1){4, 5}
–silentwf

122

如果您使用Guava(以前的Google Collections)库,则有一个解决方案:

SetView<Number> difference = com.google.common.collect.Sets.difference(test2, test1);

返回的SetViewSet,它是实时表示,您可以将其设为不可变或复制到另一个集合。test1test2保持原样。


6
请注意,test2和test1 的顺序很重要。还有symmetricDifference(),顺序无关紧要。
datv

1
symmetricDifference()除了交叉路口以外,都会带走所有其他东西,这不是原始问题所要的。
Allenaz

16

是:

test2.removeAll(test1)

尽管这会发生变异test2,但如果需要保留副本,请创建一个副本。

另外,您可能<Integer>不是<int>


7

Java 8

我们可以使用removeIf,它使用一个谓词将实用程序方法编写为:

// computes the difference without modifying the sets
public static <T> Set<T> differenceJava8(final Set<T> setOne, final Set<T> setTwo) {
     Set<T> result = new HashSet<T>(setOne);
     result.removeIf(setTwo::contains);
     return result;
}

如果我们仍旧使用某些早期版本,则可以将removeAll用作:

public static <T> Set<T> difference(final Set<T> setOne, final Set<T> setTwo) {
     Set<T> result = new HashSet<T>(setOne);
     result.removeAll(setTwo);
     return result;
}

3

如果您使用的是Java 8,则可以尝试执行以下操作:

public Set<Number> difference(final Set<Number> set1, final Set<Number> set2){
    final Set<Number> larger = set1.size() > set2.size() ? set1 : set2;
    final Set<Number> smaller = larger.equals(set1) ? set2 : set1;
    return larger.stream().filter(n -> !smaller.contains(n)).collect(Collectors.toSet());
}

4
@Downvoter:也许您没有意识到其他答案没有检查出哪个Set更大...因此,如果您尝试Set从更大的值中减去一个较小的a Set,则会收到不同的结果。
乔什M

40
您假设该函数的使用者始终想减去较小的集合。集合差异是反交换的(en.wikipedia.org/wiki/Anticommutativity)。AB!= BA
西蒙(Simon)

7
无论您实现哪种差异,我都将其public static <T> Set<T> difference(final Set<T> set1, final Set<T> set2) {用作签名,然后该方法可用作通用实用程序函数。
kap

1
@kap,但随后添加一个Comparator<T>可以自定义比较,因为equals这并不总是足够的。
gervais.b

6
由于差异操作的顺序可能会在用户不知情的情况下切换,这将导致意外结果。从较小的集减去较大的集在数学上是明确定义的,并且有很多用例。
乔尔·科内特

3

您可以CollectionUtils.disjunction用来获取所有差异或CollectionUtils.subtract在第一个集合中获取差异。

这是如何执行此操作的示例:

    var collection1 = List.of(1, 2, 3, 4, 5);
    var collection2 = List.of(2, 3, 5, 6);
    System.out.println(StringUtils.join(collection1, " , "));
    System.out.println(StringUtils.join(collection2, " , "));
    System.out.println(StringUtils.join(CollectionUtils.subtract(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.retainAll(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.collate(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.disjunction(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.intersection(collection1, collection2), " , "));
    System.out.println(StringUtils.join(CollectionUtils.union(collection1, collection2), " , "));

3
哪个项目CollectionUtils来自?1是否必须假设它来自Apache Commons Collection?
Buhake Sindi

0

仅在此处举一个示例(系统在中existingState,我们想找到要删除的元素(不在中newState但存在的existingState元素)和要添加的元素(在中newState但不存在的元素existingState):

public class AddAndRemove {

  static Set<Integer> existingState = Set.of(1,2,3,4,5);
  static Set<Integer> newState = Set.of(0,5,2,11,3,99);

  public static void main(String[] args) {

    Set<Integer> add = new HashSet<>(newState);
    add.removeAll(existingState);

    System.out.println("Elements to add : " + add);

    Set<Integer> remove = new HashSet<>(existingState);
    remove.removeAll(newState);

    System.out.println("Elements to remove : " + remove);

  }
}

结果将输出:

Elements to add : [0, 99, 11]
Elements to remove : [1, 4]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.