我有几个类,如下
class Pojo {
List items;
}
class Item {
T key1;
List subItems;
}
class SubItem {
V key2;
Object otherAttribute1;
}
我想基于key1聚合项目,对于每个聚合,子项应由key2按以下方式聚合:
Map>
Java 8 Collectors.groupingBy嵌套是如何实现的?
我正在尝试一些东西并且中途停留
pojo.getItems()
.stream()
.collect(
Collectors.groupingBy(Item::getKey1, /* How to group by here SubItem::getKey2*/)
);
注意:这与级联分组不同,后者根据here中讨论的同一对象中的字段进行多级聚合
解决方法:
您不能通过多个键对单个项目进行分组,除非您接受该项目可能出现在多个组中.在这种情况下,您想要执行一种flatMap操作.
实现此目的的一种方法是使用Stream.flatMap和一个临时对,在收集之前保存Item和SubItem的组合.由于缺少标准对类型,典型的解决方案是使用Map.Entry:
Map>> result = pojo.getItems().stream()
.flatMap(item -> item.subItems.stream()
.map(sub -> new AbstractMap.SimpleImmutableEntry<>(item, sub)))
.collect(Collectors.groupingBy(e -> e.getKey().getKey1(),
Collectors.mapping(Map.Entry::getValue,
Collectors.groupingBy(SubItem::getKey2))));
不需要这些临时对象的替代方法是在收集器中执行flatMap操作,但遗憾的是,直到Java 9,flatMapping才会出现.
有了它,解决方案看起来像
Map>> result = pojo.getItems().stream()
.collect(Collectors.groupingBy(Item::getKey1,
Collectors.flatMapping(item -> item.getSubItems().stream(),
Collectors.groupingBy(SubItem::getKey2))));
如果我们不想等待Java 9,我们可能会在代码库中添加一个类似的收集器,因为它实现起来并不难:
static Collector flatMapping(
Function super T,? extends Stream extends U>> mapper,
Collector super U,A,R> downstream) {
BiConsumer acc = downstream.accumulator();
return Collector.of(downstream.supplier(),
(a, t) -> { try(Stream extends U> s=mapper.apply(t)) {
if(s!=null) s.forEachOrdered(u -> acc.accept(a, u));
}},
downstream.combiner(), downstream.finisher(),
downstream.characteristics().toArray(new Collector.Characteristics[0]));
}
标签:java,java-8,java-stream,lambda,collections
来源: https://codeday.me/bug/20190916/1807042.html