Рубрики
Без рубрики

Набор операций в Java

Узнайте о различиях между объединением, пересечением и относительным дополнением, а также о том, как представить каждое из них в Java.

Автор оригинала: baeldung.

1. введение

Набор – это удобный способ представить уникальную коллекцию предметов.

В этом уроке мы узнаем больше о том, что это значит и как мы можем использовать его в Java.

2. Немного теории множеств

2.1. Что Такое Набор?

Набор-это просто группа уникальных вещей. Итак, существенной характеристикой любого набора является то, что он не содержит дубликатов .

Мы можем поместить в набор все, что захотим. Однако мы обычно используем наборы для группировки вещей, которые имеют общую черту. Например, у нас может быть набор транспортных средств или набор животных.

Давайте используем два набора целых чисел в качестве простого примера:

setA : {1, 2, 3, 4}

setB : {2, 4, 6, 8}

Мы можем показать наборы в виде диаграммы, просто поместив значения в круги:

Диаграмма Венна из двух наборов

Подобные диаграммы известны как диаграммы Венна и дают нам полезный способ показать взаимодействие между наборами, как мы увидим позже.

2.2. Пересечение множеств

Термин пересечение означает общие значения различных множеств .

Мы видим, что целые числа 2 и 4 существуют в обоих наборах. Таким образом, пересечение setA и setB равно 2 и 4, потому что это значения, которые являются общими для обоих наших наборов.

setA intersection setB = {2, 4}

Чтобы показать пересечение на диаграмме, мы объединяем наши два набора и выделяем область, общую для обоих наших наборов:

Диаграмма перехвата Венна

2.3. Объединение множеств

Термин объединение означает объединение значений различных наборов .

Итак, давайте создадим новый набор, который является объединением наших наборов примеров. Мы уже знаем, что у нас не может быть повторяющихся значений в наборе. Однако наши наборы имеют некоторые повторяющиеся значения (2 и 4). Поэтому, когда мы объединяем содержимое обоих наборов, нам нужно убедиться, что мы удалили дубликаты. Таким образом, мы получаем 1, 2, 3, 4, 6 и 8.

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

Опять же, мы можем показать объединение на диаграмме. Итак, давайте объединим наши два набора и выделим область, которая представляет объединение:

Диаграмма Венна объединения

2.4. Относительное дополнение множеств

Термин относительное дополнение означает значения из одного набора, которых нет в другом . Это также называется разницей в наборе.

Теперь давайте создадим новые наборы, которые являются относительными дополнениями наборов и setB .

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

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

А теперь давайте выделим область в zeta , которая не является частью set B . Это дает нам относительное дополнение set in set A :

Диаграмма Венна относительного дополнения

2.5. Подмножество и Надмножество

Подмножество-это просто часть большего набора, и больший набор называется надмножеством. Когда у нас есть подмножество и надмножество, объединение этих двух равно надмножеству, а пересечение равно подмножеству.

3. Реализация Операций Набора С java.util.Set

Чтобы увидеть, как мы выполняем операции с наборами в Java, мы возьмем примеры наборов и реализуем пересечение, объединение и относительное дополнение. Итак, давайте начнем с создания наших выборочных наборов целых чисел:

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

3.1. Пересечение

Во-первых, мы собираемся использовать метод retainAll для создания пересечения наших выборочных наборов . Поскольку retainAll изменяет набор напрямую, мы сделаем копию setA под названием intersectSet. Затем мы будем использовать метод retainAll , чтобы сохранить значения, которые также находятся в set B :

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

3.2. Союз

Теперь давайте используем метод addAll для создания объединения наших наборов образцов . Метод addAll добавляет все элементы поставляемого набора в другой. Опять же, поскольку add All обновляет набор напрямую, мы сделаем копию setA под названием union Set , а затем добавим к нему sub :

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

3.3. Относительное дополнение

Наконец, мы будем использовать метод removeAll для создания относительного дополнения set B в set A . Мы знаем, что нам нужны значения, которые находятся в множествах , которые не существуют в множестве B . Поэтому нам просто нужно удалить все элементы из наборов , которые также находятся в наборе B :

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

4. Реализация операций набора с потоками

4.1. Пересечение

Давайте создадим пересечение наших множеств с помощью Потоков .

Во-первых, мы получим значения из setA в поток. Затем мы отфильтруем поток, чтобы сохранить все значения, которые также находятся в set B . И, наконец, мы соберем результаты в новый Набор :

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

4.2. Союз

Теперь давайте используем статический метод Streams.concat , чтобы добавить значения наших наборов в один поток .

Чтобы получить объединение из объединения наших наборов, нам нужно удалить все дубликаты. Мы сделаем это, просто собрав результаты в Набор :

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

4.3. Относительное Дополнение

Наконец, мы создадим относительное дополнение set B в set A .

Как и в примере с пересечением, мы сначала получим значения из set в поток. На этот раз мы отфильтруем поток, чтобы удалить все значения, которые также находятся в set B . Затем мы соберем результаты в новый Набор :

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

5. Служебные библиотеки для операций набора

Теперь, когда мы увидели, как выполнять базовые операции набора с помощью чистой Java, давайте использовать несколько служебных библиотек для выполнения тех же операций. Одна приятная вещь в использовании этих библиотек заключается в том, что имена методов четко сообщают нам, какая операция выполняется.

5.1. Зависимости

Чтобы использовать коллекции Guava Sets и Apache Commons SetUtils , нам нужно добавить их зависимости:


    com.google.guava
    guava
    27.1-jre


    org.apache.commons
    commons-collections4
    4.3

5.2. Наборы Гуавы

Давайте используем класс Guava Sets для выполнения пересечения и объединения на наших примерах наборов. Для этого мы можем просто использовать статические методы union и intersection класса Sets :

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

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

Взгляните на нашу статью о наборах гуавы, чтобы узнать больше.

5.3. Коллекции Apache Commons

Теперь давайте использовать статические методы intersection и union класса SetUtils из коллекций Apache Commons:

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

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

Чтобы узнать больше, ознакомьтесь с нашим учебником по Apache Commons Collections SetUtils.

6. Заключение

Мы видели обзор того, как выполнять некоторые основные операции с наборами, а также подробную информацию о том, как реализовать эти операции различными способами.

Все примеры кода можно найти на GitHub .