Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collect set of objects from nested streams

I have a scenario where I have two for loops, one nested inside the other. In the inner loop, for each iteration, I have the information I need to create a new instance of a particular type. I wanted to change the code from for loops to using streams so I could collect all objects into an ImmutableSet. However, I couldn't make a version which compiles and works. My example program below illustrates my closest attempt. It compiles, but one of the parameters is hardcoded.

How can I fix the stream below so that when I allocate Bar, I have both variables s and n available?

class Bar {
  private final String s;
  private final Integer n;

  Bar(String s, Integer n) {
    this.s = s;
    this.n = n;
  }
}

public class Foo {

  private static List<Integer> getList(String s) {
    return Lists.newArrayList(s.hashCode());
  }

  Foo() {
    ImmutableSet<Bar> set = ImmutableSet.of("foo", "bar", "baz")
            .stream()
            .flatMap(s -> getList(s).stream())
            .map(n -> new Bar("", n)) // I need to use s here, not hard-code
            .collect(ImmutableSet.toImmutableSet());
  }
}
like image 436
Eric Lilja Avatar asked Mar 29 '18 12:03

Eric Lilja


1 Answers

Seems like you're looking for something along the lines of:

.flatMap(s -> getList(s).stream().map(n -> new Bar(s, n)))

Simply, chain another map operation to getList(s).stream() to transform the data, thus enabling you to have both the string and integers in scope.

Note, you're not just limited to getList(s).stream(). Meaning one can chain as many complex operations together as they want as long as the function passed to flatMap returns a Stream<R> it will compile.

like image 173
Ousmane D. Avatar answered Sep 24 '22 22:09

Ousmane D.