You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java Streams中分组计算两个属性总和的商

Java Stream分组计算总和比值的实现

需求:给定TestRecord对象的Stream,按type字段分组,计算每组中属性a的总和与属性b的总和的商,返回Map<String, Double>格式结果(示例:{TYPE1=0.66, TYPE2=0.875})。禁止使用for循环或forEach方法。

现有代码框架:

import java.util.Map;
import java.util.stream.Stream;

record TestRecord(String type, int a, int b) {
    public int getA() { return a; }
    public int getB() { return b; }
}
    
public class Test {    
    public static void main(String[] args) {
        Stream<TestRecord> testRecords = Stream.of(
            new TestRecord("TYPE1", 1, 2),
            new TestRecord("TYPE1", 3, 4),
            new TestRecord("TYPE2", 5, 6),
            new TestRecord("TYPE2", 7, 8),
            new TestRecord("TYPE2", 9, 10)
        );
    }
    
    // 预期返回 {TYPE1= (4/6), TYPE2 = (21 / 24)}
    // TYPE1: (1+3)/(2+4), TYPE2: ((5+7+9)/(6+8+10))
    public static Map<String, Double> myFunction(Stream<TestRecord> testRecordStream) {
        // TODO 实现逻辑
        return null;
    }
}

实现方案

Java 12+ 简洁版本

利用Collectors.teeing同时收集两组总和,再计算比值:

import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

record TestRecord(String type, int a, int b) {
    public int getA() { return a; }
    public int getB() { return b; }
}
    
public class Test {    
    public static void main(String[] args) {
        Stream<TestRecord> testRecords = Stream.of(
            new TestRecord("TYPE1", 1, 2),
            new TestRecord("TYPE1", 3, 4),
            new TestRecord("TYPE2", 5, 6),
            new TestRecord("TYPE2", 7, 8),
            new TestRecord("TYPE2", 9, 10)
        );
        
        Map<String, Double> result = myFunction(testRecords);
        System.out.println(result); // 输出 {TYPE1=0.6666666666666666, TYPE2=0.875}
    }
    
    public static Map<String, Double> myFunction(Stream<TestRecord> testRecordStream) {
        return testRecordStream.collect(Collectors.groupingBy(
            TestRecord::type,
            Collectors.teeing(
                Collectors.summingInt(TestRecord::getA),
                Collectors.summingInt(TestRecord::getB),
                (sumA, sumB) -> sumB == 0 ? 0.0 : (double) sumA / sumB
            )
        ));
    }
}

代码说明

  1. 分组逻辑:Collectors.groupingBy(TestRecord::type)按type字段分组,键为类型字符串,值为对应组的计算结果。
  2. 双收集器计算:Collectors.teeing同时用两个summingInt收集器,分别计算每组a和b的总和。
  3. 比值计算:合并函数中把总和转为double计算商,同时处理sumB为0的边界情况(此处返回0.0,可按需调整为抛出异常)。

Java 8+ 兼容版本

如果使用Java 12以下版本,可通过reducing合并总和后转换结果:

public static Map<String, Double> myFunction(Stream<TestRecord> testRecordStream) {
    return testRecordStream.collect(Collectors.groupingBy(
        TestRecord::type,
        Collectors.reducing(
            new int[]{0, 0}, // 初始值:sumA=0, sumB=0
            record -> new int[]{record.getA(), record.getB()},
            (acc, curr) -> new int[]{acc[0] + curr[0], acc[1] + curr[1]}
        )
    )).entrySet().stream()
      .collect(Collectors.toMap(
          Map.Entry::getKey,
          entry -> {
              int[] sums = entry.getValue();
              return sums[1] == 0 ? 0.0 : (double) sums[0] / sums[1];
          }
      ));
}

这个版本先通过reducing将每组元素合并为存储sumA和sumB的数组,再将结果转换为目标Map格式。

内容的提问来源于stack exchange,提问作者Bedirhan Gökce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:50:20