我得了Map<A,B> AvsBAB分,

class A {
    Long id;
    AggregationType aggr;
}

class B {
    Long value;
}

其中,AggregationType是包含(SUM, AVG, MIN, MAX)的枚举.

我从条目集创建了一个流,我想按A.id对该条目列表进行分组,并对生成的下游的B.值应用定制聚合.

Map<Long, Double> aggregatedMap = AvsB.entrySet().stream().groupingBy(
    entry -> entry.getKey().getId(),
    Collectors.summingDouble(entry-> (double)entry.getValue().getValue())
)

我可以针对单个聚合来解决这个问题,比如本例中的sum,但我不知道如何使用从A获取的聚合来解决这个问题(即,我需要 for each 枚举使用一个切换大小写,例如,对于AVG,我将使用Collectors.averagingDouble而不是Collectors.summingDouble. 有人能帮帮忙吗?谢谢.

推荐答案

有两个问题:第一,这些收集器不具有相同的返回类型.即使您使用DoubleStreamLongStream,您也会更接近,但您仍然不会得到完全相同的返回类型.因此,我们需要做一些额外的工作来使它们返回相同的东西.例如,这可以是一个选项:

private double collectValues(AggregatorType agg, List<Long> values) {
    DoubleStream stream = values.stream().mapToDouble(x -> x + 0.0d);
    return switch (agg) {
        case AVG -> stream.average().orElseThrow();
        case SUM -> stream.sum();
        case MAX -> stream.max().orElseThrow();
        case MIN -> stream.min().orElseThrow();
        default -> throw new IllegalArgumentException();
    };
}

第二个问题是,我们不能轻易地为同一个流的元素使用不同的收集器.因此,您需要做一些不同的操作--例如,您可以分两步完成.最初,将所有B.值收集到Aggegator.Type:

public Map<AggregatorType, Double> aggregate(Map<A, B> fields) {
    Map<AggregatorType, List<Long>> valuesByType = fields.entrySet()
        .stream()
        .collect(Collectors.groupingBy(
            entry -> entry.getKey().type(),
            Collectors.mapping(
                entry -> entry.getValue().value(),
                Collectors.toList())
        ));
    // return valuesByType.stream()...
}    

然后,使用第一个代码片段中的函数收集每个List:

 return valuesByType.entrySet()
     .stream()
     .collect(Collectors.toMap(
            entry -> entry.getKey(),
            entry -> collectValues(entry.getKey(), entry.getValue())
     ));

以下是完整的故事:

@Test
void test() {
    //given
    Map<A, B> values = Map.of(
        new A(1L, AggregatorType.AVG), new B(10L),
        new A(2L, AggregatorType.AVG), new B(20L),
        new A(3L, AggregatorType.SUM), new B(30L),
        new A(4L, AggregatorType.SUM), new B(40L),
        new A(5L, AggregatorType.MAX), new B(50L),
        new A(6L, AggregatorType.MAX), new B(60L),
        new A(7L, AggregatorType.MIN), new B(70L),
        new A(8L, AggregatorType.MIN), new B(80L)
    );

    // when
    Map<AggregatorType, Double> result = aggregate(values);

    //then
    assertThat(result).isEqualTo(Map.of(
        AggregatorType.AVG, 15d,
        AggregatorType.SUM, 70d,
        AggregatorType.MAX, 60d,
        AggregatorType.MIN, 70d
    ));
}

public Map<AggregatorType, Double> aggregate(Map<A, B> fields) {
    Map<AggregatorType, List<Long>> valuesByType = fields.entrySet()
        .stream()
        .collect(Collectors.groupingBy(
            entry -> entry.getKey().type(),
            Collectors.mapping(
                entry -> entry.getValue().value(),
                Collectors.toList())
        ));
    return valuesByType.entrySet()
        .stream()
        .collect(Collectors.toMap(
            entry -> entry.getKey(),
            entry -> collectValues(entry.getKey(), entry.getValue())
        ));
}

private double collectValues(AggregatorType aggregator, List<Long> values) {
    DoubleStream stream = values.stream().mapToDouble(x -> x + 0.0d);
    return switch (aggregator) {
        case AVG -> stream.average().orElseThrow();
        case SUM -> stream.sum();
        case MAX -> stream.max().orElseThrow();
        case MIN -> stream.min().orElseThrow();
        default -> throw new IllegalArgumentException();
    };
}

如果你想了解我是如何做到这一点的,请一步一步地阅读这篇文章:https://medium.com/javarevisited/polymorphic-stream-collector-in-java-44f9008bf043?sk=b92590ad1c65a3731746404dbd53b0f7

Java相关问答推荐

如果给定层次 struct 级别,如何从其预序穿越构造n元树

在Java 8之后,HashMap的最坏情况下时间复杂度仍然是O(n)而不是O(log n)?

Select 按位运算序列

填写文本字段后锁定PDF

R.id.main给我一个红色错误,无法解析MainActivity.java中的符号main

为什么不应用类型推断?

返回响应时,CamelCase命名约定不起作用

尽管通过中断请求线程死亡,但线程仍将继续存在

如何为JavaFX Spring Boot应用程序制作Windows/MacOS/Linux安装程序

如何在Spring Boot中创建可以将值传递给配置的&Enable&Quot;注释?

Android Java:已设置但未读取SharedPreferences

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

为什么这种递归会有这样的行为?

获取所有可以处理Invent.ACTION_MEDIA_BUTTON Android 13 API33的Android包

接受类及其接口的Java类型(矛盾)

如何用Micrometer&;斯普肯

始终使用Spring Boot连接mongodb上的测试数据库

SonarQube在合并升级到java17后对旧代码提出错误

如何在Java上为循环数组从synchronized迁移到ReentrantLock

窗口启动后不久,从java.awt.Graphics disapear创建的矩形