Java 8 Nested (Multi level) group by [英] 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;
}
我想根据 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*/)
);
注意:这与级联 groupingBy
不同,它根据讨论的同一对象中的字段进行多级聚合 这里
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 perform a kind of flatMap
operation.
实现此目的的一种方法是使用 Stream.flatMap
和一个临时对,在收集之前保存 Item
和 SubItem
的组合.由于缺少标准对类型,典型的解决方案是使用 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.getKey1(), sub)))
.collect(Collectors.groupingBy(AbstractMap.SimpleImmutableEntry::getKey,
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
won't be there until 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))));
如果我们不想等待 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().toArray(new Collector.Characteristics[0]));
}
这篇关于Java 8 Nested (Multi level) group by的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!