如何使用Java 8 Streams在一次迭代中平面映射2个不同的字段?

时间:2015-12-28 09:41:58

标签: java functional-programming java-8 java-stream

如果我有一个List,其中每个元素包含2个List字段,如何在一次迭代中将所有包含的列表合并到主列表中。

换句话说,使用流以功能形式表达以下命令式代码的最佳方式是什么?

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;
        }
    }
}

2 个答案:

答案 0 :(得分:4)

您要做的是使用2个不同的收集器收集Stream管道的结果。此外,每个收集器都需要对当前Stream项的List<String>进行平面映射。

此任务没有内置收集器,但您可以使用提供此类收集器的StreamEx库:

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

此代码将两个收集器配对,将每个集平面映射为List,并将结果存储到Item中。此Item将包含您的set1set2变量。

收集器flatMapping将在Java 9(see this mail)中提供。

答案 1 :(得分:1)

只需使用两个独立的直接流操作:

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());