Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

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.

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.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are closed on this article!