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

如何基于ID识别List中重复Foo对象并合并其子集合(支持Stream)

用Java Stream高效合并重复Foo对象的方案

嘿,这个需求我之前做过类似的,完全可以用Stream来实现,而且效率还不错。核心思路就是按id分组聚合同ID的对象,再合并它们的子集合,具体来看:

一、高效识别重复对象的核心逻辑

要高效识别重复,最直接的方式就是利用哈希分组——把所有Foo对象按id作为key分到不同的组里,同一组的就是重复(同ID)的对象。Java的Collectors.groupingBy底层用的是HashMap,平均情况下分组操作的时间复杂度是O(n),非常高效,比手动遍历逐个比对要靠谱多了。

二、用Stream实现完整的合并逻辑

直接上代码,把mergeDuplicates和mergeChilds的实现都写清楚:

1. 完整代码示例

import java.util.*;
import java.util.stream.Collectors;

public class Foo {
    private String id;
    private Collection<String> childs;

    // 构造器与Getter方法,方便后续操作
    public Foo(String id) {
        this.id = id;
        this.childs = new ArrayList<>();
    }

    public Foo(String id, Collection<String> childs) {
        this.id = id;
        this.childs = new ArrayList<>(childs);
    }

    public String getId() {
        return id;
    }

    public Collection<String> getChilds() {
        return childs;
    }

    // 合并重复Foo的核心方法
    private Collection<Foo> mergeDuplicates(Collection<Foo> fooList) {
        // 处理空输入,避免NPE
        if (fooList == null || fooList.isEmpty()) {
            return Collections.emptyList();
        }

        return fooList.stream()
                // 按id分组,key为id,value为同id的Foo集合
                .collect(Collectors.groupingBy(Foo::getId))
                .entrySet()
                .stream()
                .map(entry -> {
                    List<Foo> sameIdFoos = entry.getValue();
                    // 组内只有一个对象,直接返回
                    if (sameIdFoos.size() == 1) {
                        return sameIdFoos.get(0);
                    }
                    // 从第一个对象开始,逐个合并后续对象
                    return sameIdFoos.stream()
                            .reduce(this::mergeChilds)
                            .orElseThrow();
                })
                .collect(Collectors.toList()); // 可替换为LinkedHashSet保持原顺序
    }

    // 合并两个Foo的子集合
    private Foo mergeChilds(Foo foo1, Foo foo2) {
        // 创建新对象避免修改原实例,若允许修改原对象可调整逻辑
        Collection<String> mergedChilds = new ArrayList<>(foo1.getChilds());
        // 若需要对子集合去重,可将ArrayList换成HashSet
        mergedChilds.addAll(foo2.getChilds());
        return new Foo(foo1.getId(), mergedChilds);
    }
}

2. 关键细节说明

  • 分组操作:Collectors.groupingBy(Foo::getId)一步完成重复对象的聚合,是识别重复的核心,简洁且高效。
  • 合并逻辑:用Stream.reduce替代手动循环,代码更简洁;分组后的集合不会为空,所以orElseThrow()是安全的。
  • 子集合去重:如果要求合并后的childs无重复字符串,只需把mergedChilds的实现换成HashSet,最后再转成你需要的集合类型即可。
  • 空输入处理:开头的非空判断让代码更健壮,避免空指针异常。

三、效率说明

这个方案的时间复杂度是O(n)(n为输入Foo集合的大小):

  • 分组操作是线性遍历,每个元素插入HashMap的平均时间为O(1);
  • 子集合合并时,每个child元素只会被遍历一次,整体仍保持线性复杂度。

相比手动嵌套遍历比对(O(n²)),这个方案在集合规模较大时效率提升非常明显。

内容的提问来源于stack exchange,提问作者T. Yoo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:04:05