2

如果我必须使用 Stream 基于两个不同的字段生成两个组,这是我可以采取的一种方法:

var prop1Group = beans.stream().collect(Collectors.groupingBy(Bean::getProp1));
var prop2Group = beans.stream().collect(Collectors.groupingBy(Bean::getProp2));

但是这种方法会遍历列表两次。以一种命令式的方式,我可以在单次迭代中得到相同的结果,如下所示:

var prop1Group = new HashMap<String, Set<Bean>>();
var prop2Group = new HashMap<String, Set<Bean>>();

for (var bean : beans) {
    prop1Group.computeIfAbsent(bean.getProp1(), key -> new HashSet<>()).add(bean);
    prop2Group.computeIfAbsent(bean.getProp2(), key -> new HashSet<>()).add(bean);
}

无论如何,是否可以使用流以声明方式完成相同的操作,而无需迭代两次?

4

2 回答 2

1

根据@Holger 的评论,我可以像这样用发球更声明性地写它,但这仍然需要 2N

beans.stream().collect(
                Collectors.teeing(
                        groupingBy(Bean::getProp1),
                        groupingBy(Bean::getProp2),
                        List::of)) 
于 2019-09-04T10:04:33.487 回答
1

由于您已添加vavr为标签,我还想添加另一个解决方案,即使用元组、模式匹配和折叠:

var result = list.foldLeft(
      Tuple.of(List.empty(), List.empty()),
      (lists, element) -> Match(element).of(
           Case($(Bean::getProp1), lists.map1(l -> l.append(element))),
           Case($(Bean::getProp2), lists.map2(l -> l.append(element)))
));

在这种情况下,组将存储为Tuple2.

于 2019-09-10T13:32:30.203 回答