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

Java 8 Stream:按数组指定多字段分组并累加对应元素

问题:List<String[]>分组并累加指定字段生成新集合

现有List<String[]>类型数据集,示例数据如下:

List<String[]> dataLines = List.of(
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4055", "84M", "-101.87", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4055", "120M", "-102.48", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4055", "60M", "-103.75", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4055", "120M", "-10.8", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4055", "60M", "-110.39", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4055", "120M", "-10.8", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "CZK", "12670012.4055", "60M", "-103.75", "0"},
    new String[]{"2002", "BRBTSS", "BRSTNCNTF212", "BRL", "12670012.4066", "20M", "-10.8", "0"}
);

需要生成新的List<String[]>集合newDataLine,规则为:将数组中第0、1、3、5位元素相同的项归为一组,累加每组中数组的第6位元素,预期输出如下:

["2002","BRBTSS","BRSTNCNTF212","BRL","12670012.4055","84M","-101.87","0"],
["2002","BRBTSS","BRSTNCNTF212","BRL","12670012.4055","120M","-124.08000000000001","0"],
["2002","BRBTSS","BRSTNCNTF212","BRL","12670012.4055","60M","-214.14","0"],
["2002","BRBTSS","BRSTNCNTF212","CZK","12670012.4055","60M","-103.75","0"], 
["2002","BRBTSS","BRSTNCNTF212","BRL","12670012.4066","20M","-10.8","0"]

已尝试嵌套分组代码:

Map<String, Map<String, Map<String, Map<String, Double>>>> map = 
    dataLines.stream()
    .collect(Collectors.groupingBy(
        s -> s[0],
        Collectors.groupingBy(s -> s[1],
            Collectors.groupingBy(s -> s[3],
                Collectors.groupingBy(s -> s[5],
                    Collectors.summingDouble(s -> Double.valueOf(s[6])))))
    );

得到的输出为:

{2002={BRBTSS={BRL={84M=-101.87, 60M=-214.14, 120M=-124.08000000000001}}}}

请问如何实现符合需求的分组转换?


解决方案

你已经通过嵌套Map拿到了分组后的累加值,接下来只需要将Map结构转换回目标List<String[]>即可,这里提供两种实现方式:

方式一:使用自定义分组键(推荐,Java 16+)

通过定义一个记录类封装分组依据和需要保留的字段,直接一次性完成分组与转换,无需二次遍历原数据:

// 定义分组键记录,包含分组字段和需保留的其他字段
record GroupKey(String year, String code1, String currency, String term, String code2, String amount) {}

List<String[]> newDataLine = dataLines.stream()
    // 按自定义GroupKey分组,累加第6位的数值
    .collect(Collectors.groupingBy(
        s -> new GroupKey(s[0], s[1], s[3], s[5], s[2], s[4]),
        Collectors.summingDouble(s -> Double.valueOf(s[6]))
    ))
    // 将分组结果转换为目标String[]数组
    .entrySet()
    .stream()
    .map(entry -> {
        GroupKey key = entry.getKey();
        Double sum = entry.getValue();
        return new String[]{
            key.year(),
            key.code1(),
            key.code2(),
            key.currency(),
            key.amount(),
            key.term(),
            sum.toString(),
            "0" // 第7位固定为0,若需动态取可从原数据补充
        };
    })
    .collect(Collectors.toList());

方式二:基于现有嵌套Map转换

无需创建额外类,直接遍历已生成的嵌套Map,从原数据中补充分组中未包含的字段:

List<String[]> newDataLine = new ArrayList<>();

// 遍历嵌套Map的每一层
map.forEach((year, code1Map) -> {
    code1Map.forEach((code1, currencyMap) -> {
        currencyMap.forEach((currency, termMap) -> {
            termMap.forEach((term, sum) -> {
                // 从原数据中找到该组的任意一条记录,获取第2、4、7位的值(假设同组这些值一致)
                String[] sample = dataLines.stream()
                    .filter(s -> s[0].equals(year) && s[1].equals(code1) && s[3].equals(currency) && s[5].equals(term))
                    .findFirst()
                    .orElseThrow();
                // 组装目标数组
                newDataLine.add(new String[]{
                    year,
                    code1,
                    sample[2],
                    currency,
                    sample[4],
                    term,
                    sum.toString(),
                    sample[7]
                });
            });
        });
    });
});

说明

  • 方式一效率更高,避免了二次查找原数据,代码更简洁,适合Java 16及以上版本;
  • 方式二无需额外定义类,兼容性更好,但需要遍历原数据查找样本,性能略低。

两种方式最终都会生成符合预期的newDataLine集合。


内容的提问来源于stack exchange,提问作者prachi Kadam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 08:20:32