If I have a List
where each element contains 2 List
fields, how can I merge all the contained lists in one iteration through the main list.
In other words, what's the best way to express the following imperative code in a functional form using streams?
public class App {
public static void main(String[] args) throws InterruptedException {
List<Item> items = asList(new Item(singletonList("A"), singletonList("B")),
new Item(singletonList("C"), singletonList("D"))
);
List<String> set1 = new ArrayList<>(), set2 = new ArrayList<>();
for (Item item : items) {
set1.addAll(item.set1);
set2.addAll(item.set2);
}
}
private static class Item {
public final List<String> set1, set2;
public Item(List<String> set1, List<String> set2) {
this.set1 = set1;
this.set2 = set2;
}
}
}
What you are trying to do is to collect the result of a Stream pipeline with 2 different collectors. Furthermore, each collector needs to flatmap the List<String>
of the current Stream item.
There are no built-in collectors for this task, but you can use the StreamEx library which provides such collectors:
Item item = StreamEx.of(items)
.collect(MoreCollectors.pairing(
MoreCollectors.flatMapping(i -> i.set1.stream(), Collectors.toList()),
MoreCollectors.flatMapping(i -> i.set2.stream(), Collectors.toList()),
Item::new)
);
This code pairs two collectors that flatmaps each set into a List
and stores the result into an Item
. This Item
will contain your set1
and set2
variables.
The collector flatMapping
will be available in Java 9 (see this mail).
Just use two separate, straightforward stream operations:
List<Item> items;
List<String> set1=items.stream().map(i -> i.set1).flatMap(List::stream).collect(toList());
List<String> set2=items.stream().map(i -> i.set2).flatMap(List::stream).collect(toList());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With