首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8嵌套(多级)分组依据

问Java 8嵌套(多级)分组依据
EN

Stack Overflow用户
提问于 2016-08-25 02:01:11
回答 1查看 17.7K关注 0票数 22

我有几个类似下面的类

代码语言:javascript
复制
class Pojo {
    List<Item> items;
}

class Item {
    T key1;
    List<SubItem> subItems;
}

class SubItem {
    V key2;
    Object otherAttribute1;
}

我想基于key1聚合条目,对于每个聚合,key2应该通过以下方式聚合子项:

代码语言:javascript
复制
Map<T, Map<V, List<Subitem>>

使用Java8 Collectors.groupingBy嵌套,这是如何实现的?

我尝试了一些东西,但还是坚持了一半

代码语言:javascript
复制
pojo.getItems()
    .stream()
    .collect(
        Collectors.groupingBy(Item::getKey1, /* How to group by here SubItem::getKey2*/)
    );

注意:这不同于级联groupingBy,它基于与讨论的here相同的对象中的字段进行多级聚合

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-25 02:56:00

您不能通过多个关键点对单个项进行分组,除非您接受该项可能出现在多个组中。在这种情况下,您需要执行一种flatMap操作。

要实现这一点,一种方法是在收集之前使用包含Item和SubItem组合的临时对的Stream.flatMap。由于缺少标准对类型,典型的解决方案是使用Map.Entry:

代码语言:javascript
复制
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直到Java9才会出现。

这样,解决方案看起来就像

代码语言:javascript
复制
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,我们可以在代码库中添加一个类似的收集器,因为它实现起来并不难:

代码语言:javascript
复制
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]));
}
票数 25
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39130122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档