Set Operations in Java – Java中的集合操作

最后修改: 2019年 4月 23日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

A set is a handy way to represent a unique collection of items.

集合是表示一个独特的项目集合的一种方便的方式。

In this tutorial, we’ll learn more about what that means and how we can use one in Java.

在本教程中,我们将进一步了解这意味着什么,以及我们如何在Java中使用一个。

2. A Bit of Set Theory

2.一点集合理论

2.1. What Is a Set?

2.1.什么是集合?

A set is simply a group of unique things. So, a significant characteristic of any set is that it does not contain duplicates.

一个集合只是一组独特的事物。因此,任何集合的一个重要特征是它不包含重复的东西

We can put anything we like into a set. However, we typically use sets to group together things which have a common trait. For example, we could have a set of vehicles or a set of animals.

我们可以把任何我们喜欢的东西放入一个集合。然而,我们通常使用集合来将具有共同特征的事物组合在一起。例如,我们可以有一个车辆集或一个动物集。

Let’s use two sets of integers as a simple example:

让我们用两组整数作为一个简单的例子。

setA : {1, 2, 3, 4}

setB : {2, 4, 6, 8}

We can show sets as a diagram by simply putting the values into circles:
A Venn Diagram of Two Sets

我们可以通过简单地将数值放入圆圈中,将集合显示为一个图:
A Venn Diagram of Two Sets

Diagrams like these are known as Venn diagrams and give us a useful way to show interactions between sets as we’ll see later.

像这样的图被称为维恩图,给我们提供了一种有用的方法来显示集合之间的相互作用,我们将在后面看到。

2.2. The Intersection of Sets

2.2.集合的交集

The term intersection means the common values of different sets.

术语交集意味着不同集合的共同值

We can see that the integers 2 and 4 exist in both sets. So the intersection of setA and setB is 2 and 4 because these are the values which are common to both of our sets.

我们可以看到,两个集合中都存在整数2和4。所以setA和setB的交集是2和4,因为这是我们两个集合的共同值。

setA intersection setB = {2, 4}

In order to show the intersection in a diagram, we merge our two sets and highlight the area that is common to both of our sets:
A Venn Diagram of Interception

为了在图中显示交叉点,我们将两组数据合并,并突出显示两组数据的共同区域:
A Venn Diagram of Interception

2.3. The Union of Sets

2.3.集合的联合

The term union means combining the values of different sets.

术语union意味着结合不同集合的价值

So let’s create a new set which is the union of our example sets. We already know that we can’t have duplicate values in a set. However, our sets have some duplicate values (2 and 4). So when we combine the contents of both sets, we need to ensure we remove duplicates. So we end up with 1, 2, 3, 4, 6 and 8.

因此,让我们创建一个新的集合,它是我们的例子集合的联合。我们已经知道,一个集合中不能有重复的值。然而,我们的集合有一些重复的值(2和4)。因此,当我们合并两个集合的内容时,我们需要确保删除重复的内容。所以我们最终得到了1、2、3、4、6和8。

setA union setB = {1, 2, 3, 4, 6, 8}

Again we can show the union in a diagram. So let’s merge our two sets and highlight the area that represents the union:
A Venn Diagram of Union

同样,我们可以在图表中显示联合。因此,让我们合并我们的两个集合,并突出代表联合的区域:
A Venn Diagram of Union

2.4. The Relative Complement of Sets

2.4.集合的相对补数

The term relative complement means the values from one set that are not in another. It is also referred to as the set difference.

术语相对补充是指一个集合中不在另一个集合中的值。它也被称为集合差异。

Now let’s create new sets which are the relative complements of setA and setB.

现在让我们创建新的集合,它们是setAsetB的相对补充。

relative complement of setA in setB = {6, 8}

relative complement of setB in setA = {1, 3}

And now, let’s highlight the area in setA that is not part of setB. This gives us the relative complement of setB in setA:
A Venn Diagram of Relative Complement

现在,让我们强调setA中不属于setB的区域。这就给我们提供了setBsetA中的相对补数:
A Venn Diagram of Relative Complement

2.5. The Subset and Superset

2.5.子集和超集

A subset is simply part of a larger set, and the larger set is called a superset. When we have a subset and superset, the union of the two is equal to the superset, and the intersection is equal to the subset.

一个子集只是一个更大集合的一部分,而这个更大的集合被称为超集。当我们有一个子集和超集时,两者的并集就等于超集,而交集就等于子集。

3. Implementing Set Operations With java.util.Set

3.用java.util.Set实现集合操作

In order to see how we perform set operations in Java, we’ll take the example sets and implement the intersection, union and relative complement. So let’s start by creating our sample sets of integers:

为了了解我们如何在Java中进行集合操作,我们将以集合为例,实现相交、联合和相对补数。因此,让我们从创建我们的整数样本集开始。

private Set<Integer> setA = setOf(1,2,3,4);
private Set<Integer> setB = setOf(2,4,6,8);
    
private static Set<Integer> setOf(Integer... values) {
    return new HashSet<Integer>(Arrays.asList(values));
}

3.1. Intersection

3.1.交叉点

First, we’re going to use the retainAll method to create the intersection of our sample sets. Because retainAll modifies the set directly, we’ll make a copy of setA called intersectSet. Then we’ll use the retainAll method to keep the values that are also in setB:

首先,我们将使用retainAll方法来创建我们样本集的交集。因为retainAll直接修改了集合,我们将为setA制作一份名为intersectSet.的副本,然后我们将使用retainAll方法来保留也在setB中的值。

Set<Integer> intersectSet = new HashSet<>(setA);
intersectSet.retainAll(setB);
assertEquals(setOf(2,4), intersectSet);

3.2. Union

3.2.联盟

Now let’s use the addAll method to create the union of our sample sets. The addAll method adds all the members of the supplied set to the other. Again as addAll updates the set directly, we’ll make a copy of setA called unionSet, and then add setB to it:

现在让我们使用addAll方法来创建我们样本集的联合体addAll方法将提供的集合中的所有成员添加到另一个集合中。同样,由于addAll直接更新了集合,我们将创建一个setA的副本,称为unionSet,然后将setB添加到它。

Set<Integer> unionSet = new HashSet<>(setA);
unionSet.addAll(setB);
assertEquals(setOf(1,2,3,4,6,8), unionSet);

3.3. Relative Complement

3.3.相对补强

Finally, we’ll use the removeAll method to create the relative complement of setB in setA. We know that we want the values that are in setA that don’t exist in setB. So we just need to removeAll elements from setA that are also in setB:

最后,我们将使用removeAll方法来setA中创建setB的相对补充。我们知道,我们想要的是setA中的值不存在于setB中。所以我们只需要删除setA中也在setB中的所有元素。

Set<Integer> differenceSet = new HashSet<>(setA);
differenceSet.removeAll(setB);
assertEquals(setOf(1,3), differenceSet);

4. Implementing Set Operations with Streams

4.用Streams实现集合操作

4.1. Intersection

4.1.交叉点

Let’s create the intersection of our sets using Streams.

让我们使用Streams创建我们的集合的交集。

First, we’ll get the values from setA into a stream. Then we’ll filter the stream to keep all values that are also in setB. And lastly, we’ll collect the results into a new Set:

首先,我们将从setA中获取数值到一个流中。然后我们将过滤这个流,保留所有也在setB中的值。最后,我们将把结果收集到一个新的Set中。

Set<Integer> intersectSet = setA.stream()
    .filter(setB::contains)
    .collect(Collectors.toSet());
assertEquals(setOf(2,4), intersectSet);

4.2. Union

4.2.联盟

Now let’s use the static method Streams.concat to add the values of our sets into a single stream.

现在让我们使用静态方法Streams.concat来将我们的集合的值添加到一个stream中。

In order to get the union from the concatenation of our sets, we need to remove any duplicates. We’ll do this by simply collecting the results into a Set:

为了从我们的集合的连接中得到并集,我们需要删除任何重复的部分。我们将通过简单地将结果收集到一个Set来实现。

Set<Integer> unionSet = Stream.concat(setA.stream(), setB.stream())
    .collect(Collectors.toSet());
assertEquals(setOf(1,2,3,4,6,8), unionSet);

4.3. Relative Complement

4.3.相对补差

Finally, we’ll create the relative complement of setB in setA.

最后,我们将在setA中创建setB的相对补充。

As we did with the intersection example we’ll first get the values from setA into a stream. This time we’ll filter the stream to remove any values that are also in setB. Then, we’ll collect the results into a new Set:

正如我们在相交的例子中所做的那样,我们将首先把setA中的值放入一个流中。这一次,我们将过滤这个流,删除任何也在setB中的值。然后,我们将把这些结果收集到一个新的Set中。

Set<Integer> differenceSet = setA.stream()
    .filter(val -> !setB.contains(val))
    .collect(Collectors.toSet());
assertEquals(setOf(1,3), differenceSet);

5. Utility Libraries for Set Operations

5.用于集合操作的实用程序库

Now that we’ve seen how to perform basic set operations with pure Java, let’s use a couple of utility libraries to perform the same operations. One nice thing about using these libraries is that the method names clearly tell us what operation is being performed.

现在我们已经看到了如何用纯Java执行基本的集合操作,让我们使用几个实用的库来执行同样的操作。使用这些库的一个好处是,方法的名称清楚地告诉我们正在执行什么操作。

5.1. Dependencies

5.1.依赖性

In order to use the Guava Sets and Apache Commons Collections SetUtils we need to add their dependencies:

为了使用Guava SetsApache Commons Collections SetUtils,我们需要添加它们的依赖项。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.3</version>
</dependency>

5.2. Guava Sets

5.2.番石榴套装

Let’s use the Guava Sets class to perform intersection and union on our example sets. In order to do this we can simply use the static methods union and intersection of the Sets class:

让我们使用Guava的Sets类来对我们的例子集进行intersectionunion。为了做到这一点,我们可以简单地使用Sets类的静态方法unionintersection

Set<Integer> intersectSet = Sets.intersection(setA, setB);
assertEquals(setOf(2,4), intersectSet);

Set<Integer> unionSet = Sets.union(setA, setB);
assertEquals(setOf(1,2,3,4,6,8), unionSet);

Take a look at our Guava Sets article to find out more.

请看我们的Guava Sets文章以了解更多。

5.3. Apache Commons Collections

5.3.阿帕奇共享资源集合

Now let’s use the intersection and union static methods of the SetUtils class from the Apache Commons Collections:

现在让我们使用Apache Commons集合中的intersectionunion类的静态方法SetUtils

Set<Integer> intersectSet = SetUtils.intersection(setA, setB);
assertEquals(setOf(2,4), intersectSet);

Set<Integer> unionSet = SetUtils.union(setA, setB);
assertEquals(setOf(1,2,3,4,6,8), unionSet);

Take a look at our Apache Commons Collections SetUtils tutorial to find out more.

看看我们的Apache Commons Collections SetUtils tutorial以了解更多。

6. Conclusion

6.结论

We’ve seen an overview of how to perform some basic operations on sets, as well as details of how to implement these operations in a number of different ways.

我们已经看到了如何对集合进行一些基本操作的概述,以及如何以多种不同方式实现这些操作的细节。

All of the code examples can be found over on GitHub.

所有的代码实例都可以在GitHub上找到