[英]Java 8 Nested (Multi level) group by
I have few classes like below我有几个像下面这样的课程
class Pojo {
List<Item> items;
}
class Item {
T key1;
List<SubItem> subItems;
}
class SubItem {
V key2;
Object otherAttribute1;
}
I want to aggregate the items based on key1
and for each aggregation, subitems should be aggregated by key2
in following way:我想根据
key1
聚合项目,对于每个聚合,子项目应按以下方式由key2
聚合:
Map<T, Map<V, List<Subitem>>
How is this possible with Java 8 Collectors.groupingBy
nesting? Java 8
Collectors.groupingBy
嵌套怎么可能做到这一点?
I was trying something and stuck halfway at我正在尝试一些东西,但中途停留在
pojo.getItems()
.stream()
.collect(
Collectors.groupingBy(Item::getKey1, /* How to group by here SubItem::getKey2*/)
);
Note: This not same as cascaded groupingBy
which does multilevel aggregation based on fields in the same object as discussed here注意:这与级联
groupingBy
不同,级联groupingBy
根据此处讨论的同一对象中的字段进行多级聚合
You can't group a single item by multiple keys, unless you accept the item to potentially appear in multiple groups.您不能通过多个键对单个项目进行分组,除非您接受该项目可能出现在多个组中。 In that case, you want to perform a kind of
flatMap
operation.在这种情况下,您想要执行一种
flatMap
操作。
One way to achieve this, is to use Stream.flatMap
with a temporary pair holding the combinations of Item
and SubItem
before collecting.实现此目的的一种方法是使用
Stream.flatMap
和一个临时对,在收集之前保存Item
和SubItem
的组合。 Due to the absence of a standard pair type, a typical solution is to use Map.Entry
for that:由于缺少标准对类型,典型的解决方案是使用
Map.Entry
:
Map<T, Map<V, List<SubItem>>> result = pojo.getItems().stream()
.flatMap(item -> item.subItems.stream()
.map(sub -> new AbstractMap.SimpleImmutableEntry<>(item.getKey1(), sub)))
.collect(Collectors.groupingBy(AbstractMap.SimpleImmutableEntry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.groupingBy(SubItem::getKey2))));
An alternative not requiring these temporary objects would be performing the flatMap
operation right in the collector, but unfortunately, flatMapping
won't be there until Java 9.另一种不需要这些临时对象的替代方法是在收集器中执行
flatMap
操作,但不幸的是, flatMapping
直到 Java 9 才会出现。
With that, the solution would look like有了这个,解决方案看起来像
Map<T, Map<V, List<SubItem>>> result = pojo.getItems().stream()
.collect(Collectors.groupingBy(Item::getKey1,
Collectors.flatMapping(item -> item.getSubItems().stream(),
Collectors.groupingBy(SubItem::getKey2))));
and if we don't want to wait for Java 9 for that, we may add a similar collector to our code base, as it's not so hard to implement:如果我们不想等待 Java 9,我们可以在我们的代码库中添加一个类似的收集器,因为它并不难实现:
static <T,U,A,R> Collector<T,?,R> flatMapping(
Function<? super T,? extends Stream<? extends U>> mapper,
Collector<? super U,A,R> downstream) {
BiConsumer<A, ? super U> 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]));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.