Java 8:带有列表嵌套类的收集器groupby

时间:2017-04-19 16:13:14

标签: java grouping collectors collect

我试图通过Java 8获取以下地图

fixture.whenStable().then(() => {
    expect(component.entities).toBeDefined('no entities returned');
});

如何收集包含One.one分组的地图,即地图的第一个参数。对于Two.bd。

的映射和的第二个参数

2 个答案:

答案 0 :(得分:3)

您可以使用:

List<One> list = ...;

Map<String, BigDecimal> result1 = list.stream()
    .collect(Collectors.groupingBy(One::getOne, // key is One.one
        Collectors.mapping(one -> one.getTwo().stream() // get stream of One.two
            .map(Two::getBd) // map to Bd
            .reduce(BigDecimal.ZERO, BigDecimal::add), // reduce to sum
            Collectors.reducing(BigDecimal.ZERO, BigDecimal::add) // sum sums
        )
    ));

这将对bd的所有Two求和,然后对具有相同One的{​​{1}}的总和求和。

虽然如果Java8有一个flatMapping收集器会更简单,但是Java9已经添加了一个:

one

哪会:

public 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> downstreamAccumulator = downstream.accumulator();
    return Collector.of(downstream.supplier(),
                        (r, t) -> mapper.apply(t).sequential().forEach(u -> downstreamAccumulator.accept(r, u)),
                        downstream.combiner(),
                        downstream.finisher(),
                        downstream.characteristics().stream().toArray(Collector.Characteristics[]::new));
}

答案 1 :(得分:2)

这将做你想要的:

Map<String, BigDecimal> map = ones.stream()
    .collect(Collectors.groupingBy(
        One::getOne,
        Collectors.mapping(
            one -> one.getTwo().stream()
                .map(Two::getBd)
                .reduce(BigDecimal.ZERO, BigDecimal::add),
            Collectors.reducing(
                BigDecimal.ZERO,
                BigDecimal::add))));

这会收集One.one,将每个One.two转换为BigDecimal Two.bd属性的总和,然后在重复的情况下再次减少和求和列表中的One.one

修改

@Jorn Vernee编辑的答案的第一部分与我自己的完全相同,所以在这里我提出另一种方法:

Map<String, BigDecimal> map = ones.stream()
    .collect(Collectors.toMap(
        One::getOne,
        one -> one.getTwo().stream()
            .map(Two::getBd)
            .reduce(BigDecimal.ZERO, BigDecimal::add),
        BigDecimal::add));

这里我使用的是Collectors.toMap的重载版本,它使用提供的合并函数(在本例中为BigDecimal::add)来处理冲突。