Java 8嵌套(多级)组 [英] Java 8 Nested (Multi level) group by
问题描述
我有几个类如下
class Pojo {
List<Item> items;
}
class Item {
T key1;
List<SubItem> subItems;
}
class SubItem {
V key2;
Object otherAttribute1;
}
我想根据key1聚合项目,对于每个聚合,子项由key2按以下方式聚合:
I want to aggregate the items based on key1 and for each aggregation, subitems should be aggregated by key2 in following way:
Map<T, Map<V, List<Subitem>>
如何使用Java 8 Collectors.groupingBy嵌套?
How is this possible with Java 8 Collectors.groupingBy nesting?
我在尝试一些东西,卡在中间
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
推荐答案
您不能通过多个键对单个项目进行分组,除非您接受该项目可能出现在多个组中。在这种情况下,您想要执行一种 flatMap
操作。
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 performing a kind of flatMap
operation.
一种实现方法是使用包含项
和子项$的组合的临时对使用
Stream.flatMap
c $ c>之前收集。由于缺少标准对类型,一个典型的解决方案是使用 Map.Entry
:
One way to achieve this, is to use Stream.flatMap
with a temporary pair holding the combinations of Item
and SubItem
before collecting. Due to the absence of a standard pair type, a typical solution is to use Map.Entry
for that:
Map<T, Map<V, List<SubItem>>> 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
操作权,但不幸的是, flatMapping
将不会在Java 9之前。
An alternative not requiring these temporary objects would be performing the flatMap
operation right in the collector, but unfortunately, flatMapping
will be there not until Java 9.
这样,解决方案就像
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))));
如果我们不想等待Java 9,我们可以添加一个类似的收集器到我们的代码库,因为它不难实现:
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:
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().stream().toArray(Collector.Characteristics[]::new));
}
这篇关于Java 8嵌套(多级)组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!