Getting the difference between two sets

2020-01-24 11:21发布

问题:

So if I have two sets:

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

Is there a way to compare them and only have a set of 4 and 5 returned?

回答1:

Try this

test2.removeAll(test1);

Set#removeAll

Removes from this set all of its elements that are contained in the specified collection (optional operation). If the specified collection is also a set, this operation effectively modifies this set so that its value is the asymmetric set difference of the two sets.



回答2:

If you use Guava (former Google Collections) library there is a solution:

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

The returned SetView is a Set, it is a live representation you can either make immutable or copy to another set. test1 and test2 are left intact.



回答3:

Yes:

test2.removeAll(test1)

Although this will mutate test2, so create a copy if you need to preserve it.

Also, you probably meant <Integer> instead of <int>.



回答4:

Java 8

We can make use of removeIf which takes a predicate to write a utility method as:

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

And in case we are still at some prior version then we can use removeAll as:

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


回答5:

If you are using Java 8, you could try something like this:

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


回答6:

You can use CollectionUtils.disjunction to get all differences or CollectionUtils.subtract to get the difference in the first collection.

Here is an example of how to do that:

    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), " , "));


回答7:

Just to put one example here (system is in existingState, and we want to find elements to remove (elements that are not in newState but are present in existingState) and elements to add (elements that are in newState but are not present in 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);

  }
}

would output this as a result:

Elements to add : [0, 99, 11]
Elements to remove : [1, 4]


标签: java set