比较 Java 中的集合;操作在两个方向上都没有按预期工作

Comparing sets in Java; operation does not work as expected in both directions

创建了两组不同大小但有一些共同元素的意图是识别每组中使其与另一组不同的元素。 Java中的Setclass好像有一个不错的方法:removeAll。我做了以下事情:

import java.util.*;

public class HelloWorld {

    @SuppressWarnings("unchecked")
    public static void main(String args[]) {

        // Create a new set
        Set<String> mySet1 = new HashSet();

        // Add elements
        mySet1.add("1");
        mySet1.add("2");
        mySet1.add("4");
        mySet1.add("5");
        mySet1.add("6");
        mySet1.add("7");

        // Print the elements of the Set1
        System.out.println("mySet1: " + mySet1);

        // Create a new set
        Set<String> mySet2 = new HashSet();

        // Add elements
        mySet2.add("1");
        mySet2.add("2");
        mySet2.add("3");
        mySet2.add("5");
        mySet2.add("6");
        mySet2.add("7");
        mySet2.add("8");

        System.out.println("mySet2: " + mySet2);

        // Compare the two sets
        System.out.println("MySet1 matches mySet2: " + mySet1.equals(mySet2));

        // Remove all elements of mySet2 from mySet1
        Set<String> deletions = mySet1;
        deletions.removeAll(mySet2);
        System.out.println("deletions: " + deletions);

        // Remove all elements of mySet1 from mySet2
        Set<String> updates = mySet2;
        updates.removeAll(mySet1);
        System.out.println("updates: " + updates);
    }
}

结果是:

mySet1: [1, 2, 4, 5, 6, 7]
mySet2: [1, 2, 3, 5, 6, 7, 8]
MySet1 matches mySet2: false
deletions: [4]
updates: [1, 2, 3, 5, 6, 7, 8]

为什么 'updates' [3,8] 的结果不是?

Set<String> deletions = mySet1;
deletions.removeAll(mySet2);

您刚刚从 mySet1 中删除了所有 mySet2。将另一个变量分配给一个对象并不会复制该对象。您可以使用 HashSet 的构造函数轻松复制它:

Set<String> deletions = new HashSet<String>(mySet1);
deletions.removeAll(mySet2);
由于 Set<String> deletions = mySet1 赋值,

deletionsmySet1 指代相同的集合。因此 deletions.removeAll 从原始集合 mySet1 中删除了元素,因此第二个 removeAll 收到了一个仅包含“4”的集合。

您应该创建原始 Set 的副本,以免 mySet1mySet2 发生变异:

Set<String> deletions = new HashSet<>(mySet1); // create a copy of mySet1
deletions.removeAll(mySet2);
System.out.println("deletions: " + deletions);

// Remove all elements of mySet1 from mySet2
Set<String> updates = new HashSet<>(mySet2); // create a copy of mySet2
updates.removeAll(mySet1);
System.out.println("updates: " + updates);

在下一行中,您已将删除引用分配给 mySet1 对象,因此现在删除和 mySet1 都指向同一个对象。 设置删除 = mySet1; 稍后您删除了包含在 mySet2 中的所有 deletions 元素,这使得 deletions 只剩下一个元素 4。因为 mySet1 和 deletions 都指向同一个对象,所以这意味着 mySet1 还剩下一个元素 4。 当您尝试从 mySet2 中删除 mySet1 的所有元素时,它只会尝试从 mySet2 中删除元素 4。因此输出。

您在此处执行的操作称为 symmetric difference。您正在寻找 A - B 和 B - A 中的元素的并集(使用集合减法)。

您的代码会覆盖您的原始集,因此创建新的 Set 应该是一件简单的事情,确保操作不会改变任何东西。

// Remove all elements of mySet2 from mySet1
Set<String> deletions = new HashSet<>(mySet1);
deletions.removeAll(mySet2);
System.out.println("deletions: " + deletions);

// Remove all elements of mySet1 from mySet2
Set<String> updates = new HashSet<>(mySet2);
updates.removeAll(mySet1);
System.out.println("updates: " + updates);

或者,Google Guava provides a Sets utility which has a symmetricDifference方法:

// prints the numbers 4, 3, and 8 in no guaranteed order
System.out.println(Sets.symmetricDifference(mySet1, mySet2));

使用以下代码:

Set<String> deletions = mySet1;

您又创建了一个对相同 set.Both 删除和 mySet1 的引用 现在有 2 个变量指向相同的 set.With 下一行,您已更改此集合的内容。

deletions.removeAll(mySet2);

实际上,现在 mySet1 也将只包含删除包含的元素,因为它们都只是指向同一集合的引用。这就是为什么使用以下代码会得到意想不到的结果

updates.removeAll(mySet1);

您需要创建一个单独的集合副本,这样您就可以得到结果,您 expect.You 可以通过以下方式做到这一点:

Set<String> deletions = new HashSet<>(mySet1);