Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intersection of stream of sets into new set

Is there a better, simpler approach to this problem?

@Test
public void testReduce() {
    Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9);
    Set<Integer> bar = ImmutableSet.of(1,3,8,5,11);

    //DO think about solution for 1..n sets, and not only two.
    Set<Integer> intersection = ImmutableList.of(foo,bar)
            .stream()
            .reduce( null, (a, b) -> {
                if ( a == null ) {
                    a = new HashSet<Integer>(b);
                }
                else {
                    a.retainAll(b);
                }
                return a;
            });
    assertThat( intersection, is( ImmutableSet.of( 1,3,8) ) );
}
like image 233
Gábor Lipták Avatar asked Jul 08 '16 12:07

Gábor Lipták


People also ask

What is set intersection in Java?

The Intersection of Sets. The term intersection means the common values of different sets. We can see that the integers 2 and 4 exist in both sets. So the intersection of setA and setB is 2 and 4 because these are the values which are common to both of our sets.

How to do intersection of two lists in Java?

Intersection of Two Lists of StringsList<String> list = Arrays. asList("red", "blue", "blue", "green", "red"); List<String> otherList = Arrays. asList("red", "green", "green", "yellow");

How do you find the intersection in Java?

Sets intersection() function | Guava | Java The returned set contains all elements that are contained by both backing sets. The iteration order of the returned set matches that of set1. Return Value: This method returns an unmodifiable view of the intersection of two sets.

Can you stream a set?

Being a type of Collection, we can convert a set to Stream using its stream() method.


1 Answers

reduce is the wrong method for this, as you are not allowed to modify the function’s argument this way. This is a mutable reduction, also known as collect:

List<Set<Integer>> listOfSets=…;

if (listOfSets.isEmpty()) {
  return new HashSet<>();
}

Set<Integer> intersection = listOfSets.stream().skip(1)
    .collect(()->new HashSet<>(listOfSets.get(0)), Set::retainAll, Set::retainAll);

Having to peek for the first set is a drawback here, but using null as identity value isn’t clean either (and wouldn’t work with collect as the accumulator can’t return a new set).

like image 103
Holger Avatar answered Sep 19 '22 20:09

Holger