Java 8嵌套(多级)组 [英] Java 8 Nested (Multi level) group by

查看:1520
本文介绍了Java 8嵌套(多级)组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个类如下

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屋!

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