如果我有两个集合:

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 ?


Yes:

test2.removeAll(test1)

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

此外,您可能指的是<Integer>而不是<int>。


试试这个

test2.removeAll(test1);

组# removeAll

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


如果你正在使用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());
}

如果你使用Guava(前谷歌集合)库有一个解决方案:

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

返回的SetView是一个Set,它是一个动态表示,你可以使它不可变或复制到另一个Set。Test1和test2保持不变。


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

您可以使用Apache Commons CollectionUtils。disjunction来获得所有的差异,或者CollectionUtils。相减得到第一个集合中的差值。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

下面是一个如何做到这一点的例子:

import org.apache.commons.collections4.CollectionUtils;
import java.util.List;

var collection1 = List.of(-1, 0, 1, 2, 3, 4, 5);
var collection2 = List.of(       1, 2, 3, 4, 5, 6, 7, 8, 9);

// [-1, 0, 1, 2, 3, 4, 5]
System.out.println(collection1);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
System.out.println(collection2);

// [-1, 0]
System.out.println(CollectionUtils.subtract(collection1, collection2));
// [6, 7, 8, 9]
System.out.println(CollectionUtils.subtract(collection2, collection1));

// [1, 2, 3, 4, 5]
System.out.println(CollectionUtils.retainAll(collection1, collection2));
// [1, 2, 3, 4, 5]
System.out.println(CollectionUtils.retainAll(collection2, collection1));

// [-1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9]
System.out.println(CollectionUtils.collate(collection1, collection2));
// [-1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9]
System.out.println(CollectionUtils.collate(collection2, collection1));

// [-1, 0, 6, 7, 8, 9]
System.out.println(CollectionUtils.disjunction(collection1, collection2));
// [-1, 0, 6, 7, 8, 9]
System.out.println(CollectionUtils.disjunction(collection2, collection1));

// [1, 2, 3, 4, 5]
System.out.println(CollectionUtils.intersection(collection1, collection2));
// [1, 2, 3, 4, 5]
System.out.println(CollectionUtils.intersection(collection2, collection1));

// [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
System.out.println(CollectionUtils.union(collection1, collection2));
// [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
System.out.println(CollectionUtils.union(collection2, collection1));

举个例子(system在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]

您可以使用. addall()创建两个集合的联合,使用. retainall()创建交集,并使用. removeif()从联合中删除交集(或复制的元素)。

HashSet union = new HashSet(group1);
union.addAll(group2);
        
System.out.println("Union: " + union);
        
HashSet intersection = new HashSet(group1);
intersection.retainAll(group2);
        
System.out.println("Intersection: " + intersection);
        
HashSet difference = new HashSet(union);
difference.removeIf(n -> (difference.contains(intersection)));
        
System.out.println("Difference: " + difference);

添加一个解决方案,我最近用过,没有看到这里提到。如果你有Apache Commons Collections可用,那么你可以使用SetUtils#difference方法:

// Returns all the elements of test2 which are not in test1
SetUtils.difference(test2, test1) 

注意,根据文档,返回的集合是一个不可修改的视图:

返回一个不可修改的视图,其中包含给定集合的差值,用a \ b(或a - b)表示。 返回的视图包含a中不属于b的所有元素。

完整文档:https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/SetUtils.html#difference-java.util.Set-java.util.Set-


顺序很重要,因为你需要4和5是int(不是Integer), 使用test2.removeAll (test1)。


参考Bojan Vukasovic的回答,这里有一个更完整的答案。

它实际上返回一个delta,提供添加和删除的元素列表。

将集合传递给delta方法的顺序很重要。

要获得delta:

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

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

var delta = Sets.delta(test1, test2);

delta.additions.equals(Set.of(4,5));
delta.subtractions.equals(Set.of(9));
package dev.onepub.util;

import java.util.HashSet;
import java.util.Set;

public class Sets
{
    /**
     * Calculates the delta of the two sets.
     * 
     * The method assumes that you have an existing set
     * that has been revised.
     * 
     * The delta is expressed as:
     *  additions - the list of items FOUND in the revised set, that are not in the existing set.
     *  subtractions - the list of items NOT in the revised set, that are in the existing set.
     *  
     * The existing and revised sets are left unchanged.
     * 
     * @param <T>
     * @param existing - the original set used as the baseline 
     * @param revised - the revised set which will be compared against the existing set.
     * @return a SetDelta that describes the set of changes.
     */
    static public <T> SetDelta<T> delta(Set<T> existing, Set<T> revised)
    {
        var additions = new HashSet<>(revised);
        additions.removeAll(existing);

        var subtractions = new HashSet<>(existing);
        subtractions.removeAll(revised);

        return new SetDelta<T>(additions, subtractions);
    }
    
    /**
     * Describes the changes between two sets. 
     * @author bsutton
     *
     * @param <T> the type of entity held by the set.
     */
    static public class SetDelta<T>
    {
        public SetDelta(HashSet<T> additions, HashSet<T> subtractions)
        {
            this.additions = additions;
            this.subtractions = subtractions;
        }

        // The set of additional items
        final public Set<T> additions;
        
        // The set of removed items.
        final public Set<T> subtractions;

    }
}


单元测试

package dev.onepub.util;

import static org.junit.jupiter.api.Assertions.*;

import java.util.Set;

import org.junit.jupiter.api.Test;

class SetsTest
{

    @Test
    void test()
    {
        Set<Integer> existingState = Set.of(1, 2, 3, 4, 5);
        Set<Integer> newState = Set.of(0, 5, 2, 11, 3, 99);

        var delta = Sets.delta(existingState, newState);

        assertEquals(delta.additions, Set.of(0, 99, 11));
        assertEquals(delta.subtractions, Set.of(1, 4));
    }

    
    @Test
    void testSame()
    {
        Set<Integer> existingState = Set.of(1,2);
        Set<Integer> newState = Set.of(1,2);

        var delta = Sets.delta(existingState, newState);

        assertEquals(delta.additions, Set.of());
        assertEquals(delta.subtractions, Set.of());
    }
    
    @Test
    void testBothEmpty()
    {
        Set<Integer> existingState = Set.of();
        Set<Integer> newState = Set.of();

        var delta = Sets.delta(existingState, newState);

        assertEquals(delta.additions, Set.of());
        assertEquals(delta.subtractions, Set.of());
    }
    
    @Test
    void testAddOne()
    {
        Set<Integer> existingState = Set.of();
        Set<Integer> newState = Set.of(1);

        var delta = Sets.delta(existingState, newState);

        assertEquals(delta.additions, Set.of(1));
        assertEquals(delta.subtractions, Set.of());
    }
    
    @Test
    void testRemoveOne()
    {
        Set<Integer> existingState = Set.of(1);
        Set<Integer> newState = Set.of();

        var delta = Sets.delta(existingState, newState);

        assertEquals(delta.additions, Set.of());
        assertEquals(delta.subtractions, Set.of(1));
    }
    
    @Test
    void testAddOneRemoveOne()
    {
        Set<Integer> existingState = Set.of(1);
        Set<Integer> newState = Set.of(0);

        var delta = Sets.delta(existingState, newState);

        assertEquals(delta.additions, Set.of(0));
        assertEquals(delta.subtractions, Set.of(1));
    }

}