«1. Обзор

В этом руководстве мы проиллюстрируем наиболее полезные способы использования Guava для работы с наборами Java.

Давайте начнем с простого и создадим HashSet без оператора new, используя Guava:

Set<String> aNewSet = Sets.newHashSet();

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

Во-первых, давайте посмотрим, как мы можем выполнить операцию объединения над множествами â – используя простой API Sets.union():

@Test
public void whenCalculatingUnionOfSets_thenCorrect() {
    Set<Character> first = ImmutableSet.of('a', 'b', 'c');
    Set<Character> second = ImmutableSet.of('b', 'c', 'd');

    Set<Character> union = Sets.union(first, second);
    assertThat(union, containsInAnyOrder('a', 'b', 'c', 'd'));
}

3. Декартово произведение множеств

Мы также можем получить произведение двух множеств, используя Sets.cartesianProduct(), как в следующем примере: ~~ ~

@Test
public void whenCalculatingCartesianProductOfSets_thenCorrect() {
    Set<Character> first = ImmutableSet.of('a', 'b');
    Set<Character> second = ImmutableSet.of('c', 'd');
    Set<List<Character>> result =
      Sets.cartesianProduct(ImmutableList.of(first, second));

    Function<List<Character>, String> func =
      new Function<List<Character>, String>() {
        public String apply(List<Character> input) {
            return Joiner.on(" ").join(input);
        }
    };
    Iterable<String> joined = Iterables.transform(result, func);
    assertThat(joined, containsInAnyOrder("a c", "a d", "b c", "b d"));
}

Обратите внимание: чтобы легко проверить результат, мы используем функцию и объект соединения для преобразования сложной структуры Set\u003cList\u003cCharacter\u003e\u003e в более управляемую Iterable\u003cString\u003e.

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

Далее — давайте посмотрим, как получить пересечение между двумя множествами — с помощью API Sets.intersection():

@Test
public void whenCalculatingSetIntersection_thenCorrect() {
    Set<Character> first = ImmutableSet.of('a', 'b', 'c');
    Set<Character> second = ImmutableSet.of('b', 'c', 'd');

    Set<Character> intersection = Sets.intersection(first, second);
    assertThat(intersection, containsInAnyOrder('b', 'c'));
}

5. Симметричное различие множеств ~~ ~ Теперь давайте посмотрим на симметричную разность двух наборов — всех элементов, которые содержатся либо в наборе 1, либо в наборе 2, но не в обоих:

6. Power Set

@Test
public void whenCalculatingSetSymmetricDifference_thenCorrect() {
    Set<Character> first = ImmutableSet.of('a', 'b', 'c');
    Set<Character> second = ImmutableSet.of('b', 'c', 'd');

    Set<Character> intersection = Sets.symmetricDifference(first, second);
    assertThat(intersection, containsInAnyOrder('a', 'd'));
}

Теперь — «Давайте посмотрим, как вычислить набор мощности — набор всех возможных подмножеств этого набора.

В следующем примере — мы используем Sets.powerSet() для вычисления набора мощности заданного набора символов:

7. ContiguousSet

@Test
public void whenCalculatingPowerSet_thenCorrect() {
    Set<Character> chars = ImmutableSet.of('a', 'b');

    Set<Set<Character>> result = Sets.powerSet(chars);

    Set<Character> empty =  ImmutableSet.<Character> builder().build();
    Set<Character> a = ImmutableSet.of('a');
    Set<Character> b = ImmutableSet.of('b');
    Set<Character> aB = ImmutableSet.of('a', 'b');

    assertThat(result, contains(empty, a, b, aB));
}

Далее — давайте посмотрим на отсортированный набор смежных значений — ContiguousSet.

В следующем примере мы получаем набор целых чисел [10, 11, …, 30] в ContiguousSet:

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

@Test
public void whenCreatingRangeOfIntegersSet_thenCreated() {
    int start = 10;
    int end = 30;
    ContiguousSet<Integer> set = ContiguousSet.create(
      Range.closed(start, end), DiscreteDomain.integers());

    assertEquals(21, set.size());
    assertEquals(10, set.first().intValue());
    assertEquals(30, set.last().intValue());
}

8. RangeSet

Теперь давайте посмотрим на RangeSet. Мы можем использовать RangeSet для хранения отключенных и непустых диапазонов.

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

Давайте подробно рассмотрим этот пример:

@Test
public void whenUsingRangeSet_thenCorrect() {
    RangeSet<Integer> rangeSet = TreeRangeSet.create();
    rangeSet.add(Range.closed(1, 10));
    rangeSet.add(Range.closed(12, 15));

    assertEquals(2, rangeSet.asRanges().size());

    rangeSet.add(Range.closed(10, 12));
    assertTrue(rangeSet.encloses(Range.closed(1, 15)));
    assertEquals(1, rangeSet.asRanges().size());
}

Сначала — мы вставляем 2 несвязанных диапазона: [1, 10] и [12, 15] Далее — мы добавляем третий диапазон, чтобы соединить существующие 2: [10, 12] Наконец — мы проверяем, что RangeSet был достаточно умен, чтобы посмотрите, что 3 диапазона теперь являются одним большим диапазоном, и объедините их вместе в: [1, 15]

    9. MultiSet

Далее — давайте обсудим, как использовать Multiset. В отличие от обычных наборов, мультимножество поддерживает добавление повторяющихся элементов, которые считаются вхождениями.

В следующем примере мы рассмотрим простую логику работы с несколькими наборами:

10. Получение первых N элементов в наборе нескольких наборов

@Test
public void whenInsertDuplicatesInMultiSet_thenInserted() {
    Multiset<String> names = HashMultiset.create();
    names.add("John");
    names.add("Adam", 3);
    names.add("John");

    assertEquals(2, names.count("John"));
    names.remove("John");
    assertEquals(1, names.count("John"));

    assertEquals(3, names.count("Adam"));
    names.remove("Adam", 2);
    assertEquals(1, names.count("Adam"));
}

Теперь — давайте посмотрим на более сложный и полезный пример. использования MultiSet. Мы получим первые N элементов, встречающихся в наборе — в основном, самые распространенные.

В следующем примере мы сортируем элементы в Multiset с помощью Multisets.copyHighCountFirst():

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

@Test
public void whenGetTopOcurringElementsWithMultiSet_thenCorrect() {
    Multiset<String> names = HashMultiset.create();
    names.add("John");
    names.add("Adam", 5);
    names.add("Jane");
    names.add("Tom", 2);

    Set<String> sorted = Multisets.copyHighestCountFirst(names).elementSet();
    List<String> sortedAsList = Lists.newArrayList(sorted);
    assertEquals("Adam", sortedAsList.get(0));
    assertEquals("Tom", sortedAsList.get(1));
}

В этом кратком руководстве мы обсудили наиболее распространенные и полезные варианты использования работы с наборами, использующими библиотеку Guava.

Реализацию всех этих примеров и фрагментов кода можно найти в моем проекте Guava на github — это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.

«