1. Overview
In this tutorial, weβll illustrate the most useful ways you can leverage Guava to work with Java Sets.
Letβs start very simple and create a HashSet without the new operator, using Guava:
Set<String> aNewSet = Sets.newHashSet();
2. Union of Sets
First, letβs take a look at how we can do a union operation over Sets β using the simple Sets.union() API:
@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. Cartesian Product of Sets
We can also get the product of two sets using Sets.cartesianProduct() as in the following example:
@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"));
}
Note that β to be able to test out the result easily, we are using a Function and a Joiner to convert the complex Set<List<Character>> structure into a more manageable Iterable<String>.
4. Sets Intersection
Next β letβs see how to get the intersection between two sets β using the Sets.intersection() API:
@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. Symmetric Difference of Sets
Now, letβs have a look at the symmetric difference of two sets β all elements that are contained in either set 1 or set 2 but not in both:
@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. Power Set
Now β Letβs see how to calculate the power set β the set of all possible subsets of that set.
In the following example β we use Sets.powerSet() to calculate the power set of a given set of characters:
@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
Next β Letβs take a look at a sorted set of contiguous values β the ContiguousSet.
In the following example β we get a set of integers [10, 11, β¦, 30] into a 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());
}
This type of data structure is of course something you can do in plain Java with a TreeSet β but the semantics of this specialized type of set are just much more nicer to work with if you need your data represented this way.
8. RangeSet
Now β letβs take a look at RangeSet. We can use RangeSet to hold disconnected and nonempty ranges.
In the following example β when start with 2 disconnected ranges and then we connect them into a single, large range:
@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());
}
Letβs go over this example in detail:
- First β we insert the 2 disconnected ranges: [1, 10] and [12, 15]
- Next β we add a third range to connect the existing 2: [10, 12]
- Finally β we verify that the RangeSet was smart enough to see that the 3 ranges are now one large range, and merge them together into: [1, 15]
9. MultiSet
Next β letβs discuss how to use Multiset. As opposed to normal sets, a Multiset does support adding duplicate elements β which it counts as occurrences.
In the following example β we go through some simple multi-set logic:
@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. Get Top N Elements in a MultiSet
Now β letβs see a more complex and useful example of using a MultiSet. Weβll get the Top N occurring elements in the set β basically, the most common ones.
In the following example β we sort the elements in the Multiset using 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. Conclusion
In this quick tutorial we discussed the most common and useful usecases of working with Sets using the Guava library.
