Java 8 Nested (Multi level) group by [英] Java 8 Nested (Multi level) group by

查看:20
本文介绍了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 和一个临时对,在收集之前保存 ItemSubItem 的组合.由于缺少标准对类型,典型的解决方案是使用 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆