Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to flatMap 2 different fields in one iteration with Java 8 Streams?

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;
        }
    }
}
like image 868
Chandra Sekar Avatar asked Oct 12 '25 15:10

Chandra Sekar


2 Answers

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).

like image 147
Tunaki Avatar answered Oct 14 '25 05:10

Tunaki


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());
like image 45
Bohemian Avatar answered Oct 14 '25 05:10

Bohemian