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

如何用Java Stream reduce()按需合并或更新集合元素

问题:按Category合并Info对象的orderIds与price

现有一个List<Info>集合,其中每个Info对象的orderIds列表仅包含一个元素。需要基于此生成Set<Info>或List<Info>,当两个Info对象的category相同时,不新增元素,而是合并orderIds并累加price。

代码定义

class Info {
    String category;
    List<Integer> orderIds;
    int price;

    public Info(String category, List<Integer> orderIds, int price) {
        this.category = category;
        this.orderIds = orderIds;
        this.price = price;
    }
}

示例数据

private static List<Info> getInfos() {
    List<Info> infos = new ArrayList<>();

    infos.add(new Info("CATEGORY_1", Collections.singletonList(110), 200));
    infos.add(new Info("CATEGORY_1", Collections.singletonList(120), 300));
    infos.add(new Info("CATEGORY_2", Collections.singletonList(210), 1000));
    infos.add(new Info("CATEGORY_2", Collections.singletonList(220), 2000));
    infos.add(new Info("CATEGORY_3", Collections.singletonList(300), 400));
    return infos;
}

期望结果

Info("CATEGORY_1", List(110,120), 500);
Info("CATEGORY_2", List(210,220), 3000);
Info("CATEGORY_3", List(300), 400);

现有代码框架

getInfos().stream()
     .reduce(new HashSet<Info>(), ?? , ?? );

解决方案

步骤1:完善Info类

要实现按category判断对象是否重复,需要重写equals和hashCode方法;同时为了避免修改原对象的不可变集合,合并时需创建新列表:

import java.util.Objects;
import java.util.List;
import java.util.stream.Collectors;

class Info {
    String category;
    List<Integer> orderIds;
    int price;

    public Info(String category, List<Integer> orderIds, int price) {
        this.category = category;
        this.orderIds = orderIds;
        this.price = price;
    }

    // 基于category判断对象相等
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Info info = (Info) o;
        return Objects.equals(category, info.category);
    }

    @Override
    public int hashCode() {
        return Objects.hash(category);
    }

    // 重写toString方便查看结果
    @Override
    public String toString() {
        return "Info(\"" + category + "\", List(" + 
               orderIds.stream().map(String::valueOf).collect(Collectors.joining(",")) + 
               "), " + price + ")";
    }
}

步骤2:用reduce实现合并逻辑

这里使用ArrayList作为累加器(比HashSet更直观,便于处理合并逻辑),实现累加器和组合器的具体逻辑:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    private static List<Info> getInfos() {
        List<Info> infos = new ArrayList<>();
        infos.add(new Info("CATEGORY_1", Collections.singletonList(110), 200));
        infos.add(new Info("CATEGORY_1", Collections.singletonList(120), 300));
        infos.add(new Info("CATEGORY_2", Collections.singletonList(210), 1000));
        infos.add(new Info("CATEGORY_2", Collections.singletonList(220), 2000));
        infos.add(new Info("CATEGORY_3", Collections.singletonList(300), 400));
        return infos;
    }

    public static void main(String[] args) {
        List<Info> mergedInfos = getInfos().stream()
                .reduce(new ArrayList<>(), 
                        // 累加器:处理单个元素与累加集合的合并
                        (acc, current) -> {
                            acc.stream()
                                    .filter(info -> info.equals(current))
                                    .findFirst()
                                    .ifPresentOrElse(
                                            existing -> {
                                                // 合并orderIds并累加price
                                                existing.orderIds.addAll(current.orderIds);
                                                existing.price += current.price;
                                            },
                                            () -> {
                                                // 新增元素时复制orderIds,避免修改原不可变集合
                                                acc.add(new Info(current.category, new ArrayList<>(current.orderIds), current.price));
                                            }
                                    );
                            return acc;
                        },
                        // 组合器:并行流场景下合并两个中间结果集合
                        (list1, list2) -> {
                            list2.forEach(item -> {
                                list1.stream()
                                        .filter(info -> info.equals(item))
                                        .findFirst()
                                        .ifPresentOrElse(
                                                existing -> {
                                                    existing.orderIds.addAll(item.orderIds);
                                                    existing.price += item.price;
                                                },
                                                () -> list1.add(item)
                                        );
                            });
                            return list1;
                        });

        // 输出合并后的结果
        mergedInfos.forEach(System.out::println);
    }
}

补充:更简洁的Collectors.toMap实现

如果不局限于使用reduce,Collectors.toMap可以更简洁地完成需求:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

List<Info> mergedInfos = new ArrayList<>(getInfos().stream()
        .collect(Collectors.toMap(
                Info::getCategory, // 以category作为key
                info -> new Info(info.category, new ArrayList<>(info.orderIds), info.price), // 初始value为新的Info对象
                (existing, newInfo) -> {
                    // 重复key时的合并逻辑
                    existing.orderIds.addAll(newInfo.orderIds);
                    existing.price += newInfo.price;
                    return existing;
                }
        )).values());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:27:06