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"));
}
Обратите внимание: чтобы легко проверить результат, мы используем Function
и Joiner
для преобразования сложной структуры Set<List<Character>>
в более управляемую Iterable<String>
.
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, но не в обоих:
@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'));
}
6. Набор мощности
Теперь давайте посмотрим, как рассчитать набор мощности — набор всех возможных подмножеств этого набора.
В следующем примере мы используем Sets.powerSet()
для вычисления набора мощности заданного набора символов:
@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));
}
7. Непрерывный набор
Далее — давайте взглянем на отсортированный набор смежных значений — ContiguousSet
.
В следующем примере мы получаем набор целых чисел [10, 11, …, 30] в ContiguousSet
:
@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());
}
Этот тип структуры данных, конечно, можно реализовать в простой Java с помощью TreeSet
, но с семантикой этого специализированного типа набора гораздо приятнее работать, если вам нужно, чтобы ваши данные были представлены таким образом.
8. Набор диапазонов
Теперь — давайте взглянем на 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
. В отличие от обычных наборов, мультимножество поддерживает
добавление повторяющихся элементов, которые считаются вхождениями .
В следующем примере мы проходим простую логику с несколькими множествами:
@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"));
}
10. Получите первые N элементов в мультинаборе
Теперь давайте посмотрим на более сложный и полезный пример использования MultiSet
. Мы получим первые N элементов, встречающихся в наборе — в основном, самые распространенные.
В следующем примере мы сортируем элементы в Multiset
, используя Multisets.copyHighCountFirst()
:
@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));
}
11. Заключение
В этом кратком руководстве мы обсудили наиболее распространенные и полезные варианты использования сетов с помощью библиотеки Guava .
Реализацию всех этих примеров и фрагментов кода можно найти в моем проекте Guava на github — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.