Guava – Sets – 番石榴 –套

最后修改: 2014年 11月 4日


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:

首先,让我们来看看我们如何对集合进行联合操作–使用简单的Sets.union() API。

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:


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:

接下来–让我们看看如何获得两个集合的交集–使用Sets.intersection() API。

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:


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:


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:

在下面的例子中–我们得到一个整数集[10, 11, …, 30],变成一个ContiguousSet

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:


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:


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

    assertEquals(2, names.count("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():

在下面的例子中 – 我们使用Multiset.copyHighCountFirst()Multiset中的元素进行排序。

public void whenGetTopOcurringElementsWithMultiSet_thenCorrect() {
    Multiset<String> names = HashMultiset.create();
    names.add("Adam", 5);
    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.

所有这些例子和代码片段的实现可以在我的Guava github项目中找到 – 这是一个基于Eclipse的项目,所以它应该很容易导入和运行,如实。