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
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.
The implementation of all these examples and code snippets can be found in my Guava github project – this is an Eclipse based project, so it should be easy to import and run as it is.