Last active
August 1, 2019 08:30
-
-
Save ayago/7a8ce4f002e407f1644da721aad951d1 to your computer and use it in GitHub Desktop.
Bind/Flat map nested stream
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import lombok.extern.slf4j.Slf4j; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
import java.util.stream.Stream; | |
import static java.lang.String.format; | |
import static java.util.Arrays.asList; | |
@Slf4j | |
public class BindNestedStreamSample { | |
public static void main(String[] args) { | |
List<ClassA> aLists = asList( | |
new ClassA("1", | |
asList( | |
new ClassB("a", asList( | |
new ClassC("I"))))), | |
new ClassA("2", | |
asList( | |
new ClassB("a", asList( | |
new ClassC("I"), | |
new ClassC("II") | |
)))) | |
); | |
System.out.println("Imperative collect: "+imperativeCollect(aLists)); | |
System.out.println("Declarative collect: "+declarativeCollect(aLists)); | |
} | |
private static List<String> imperativeCollect(List<ClassA> aList){ | |
List<String> strings = new ArrayList<>(); | |
for (ClassA a: aList){ | |
for(ClassB b: a.bList){ | |
for(ClassC c: b.cList) { | |
String string = stringify(a).apply(b).apply(c); | |
strings.add(string); | |
} | |
} | |
} | |
return strings; | |
} | |
private static List<String> declarativeCollect(List<ClassA> aList){ | |
return bindNestedStream(BindNestedStreamSample::stringify) | |
.apply(aList.stream()) | |
.apply(a -> a.bList.stream()) | |
.apply(b -> b.cList.stream()) | |
.collect(Collectors.toList()); | |
} | |
private static Function<ClassB, Function<ClassC, String>> stringify(ClassA a){ | |
return b -> c -> format("%s-%s-%s", a.name, b.name, c.name); | |
} | |
//flattening nested streams with reference to parent. A comprehension pattern | |
//equivalent to | |
// | |
//Stream aStream; | |
//Stream bStream = a -> stream(a) | |
//Stream cStream = b -> stream(b) | |
// | |
//for(A a: aStream){ | |
// for(B b: bStream(a)){ | |
// for(C c: cStream(b)){ | |
// f(a, b, c) | |
// } | |
// } | |
//} | |
private static <A, B, C, D> Function<Stream<A>, | |
Function<Function<A, Stream<B>>, | |
Function<Function<B, Stream<C>>, Stream<D>>>> bindNestedStream( | |
Function<A, Function<B, Function<C, D>>> f) { | |
return a -> b -> c -> | |
a.flatMap(x -> | |
b.apply(x).flatMap(y -> | |
c.apply(y).map(z -> | |
f.apply(x).apply(y).apply(z) | |
) | |
) | |
); | |
} | |
private static class ClassA { | |
private final String name; | |
final List<ClassB> bList; | |
private ClassA(String name, List<ClassB> bList) { | |
this.name = name; | |
this.bList = bList; | |
} | |
} | |
private static class ClassB { | |
private final String name; | |
final List<ClassC> cList; | |
private ClassB(String name, List<ClassC> cList) { | |
this.name = name; | |
this.cList = cList; | |
} | |
} | |
private static class ClassC { | |
private final String name; | |
ClassC(String name) { | |
this.name = name; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment