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

如何基于field1或field2相等条件合并CustomObject列表项?

解决方案

要实现基于field1相等 或 field2相等的CustomObject合并需求,Collectors.toMap确实无法直接满足(因为它依赖单一维度的key进行分组)。下面提供两种实用的实现思路:

方法一:遍历匹配合并(直观易用,适合小规模列表)

核心逻辑是维护一个结果列表,逐个遍历原列表元素,在结果列表中查找是否存在符合合并条件的对象,有则合并,无则加入结果列表。

代码实现

假设你已经有自定义的合并方法customMergeMethod,可以复用它来完成合并逻辑:

// 自定义合并方法(按需求保留field3非空的对象,合并listOfString)
private CustomObject customMergeMethod(CustomObject a, CustomObject b) {
    // 确定保留的对象:优先选择field3非空的
    CustomObject keep = StringUtils.isNotBlank(a.getField3()) ? a : b;
    CustomObject mergeFrom = StringUtils.isNotBlank(a.getField3()) ? b : a;
    
    // 将待合并对象的listOfString追加到保留对象中
    keep.getListOfString().addAll(mergeFrom.getListOfString());
    
    return keep;
}

// 执行合并
List<CustomObject> mergedList = new ArrayList<>();
for (CustomObject current : list) {
    boolean isMerged = false;
    Iterator<CustomObject> iterator = mergedList.iterator();
    
    while (iterator.hasNext()) {
        CustomObject existing = iterator.next();
        // 判断是否满足合并条件:field1相等 或 field2相等
        // 若需排除空字符串匹配,可添加StringUtils.isNotBlank判断(见下方说明)
        if (Objects.equals(current.getField1(), existing.getField1()) 
            || Objects.equals(current.getField2(), existing.getField2())) {
            
            // 合并后移除原对象,添加合并后的新对象
            CustomObject mergedObj = customMergeMethod(existing, current);
            iterator.remove();
            mergedList.add(mergedObj);
            isMerged = true;
            break;
        }
    }
    
    if (!isMerged) {
        mergedList.add(current);
    }
}

注意事项

如果不希望空字符串触发合并(比如两个对象的field2都是空,但field1完全不同),可以修改判断条件,仅当字段非空且相等时才合并:

if ((StringUtils.isNotBlank(current.getField1()) && Objects.equals(current.getField1(), existing.getField1())) 
    || (StringUtils.isNotBlank(current.getField2()) && Objects.equals(current.getField2(), existing.getField2())))

方法二:并查集(Union-Find)分组合并(高效,适合大规模列表)

当列表规模较大时,遍历匹配的时间复杂度较高(O(n²)),可以用并查集将所有符合条件的对象归为同一组,再对每组内的对象进行合并。

代码实现

// 初始化并查集:每个对象的父节点初始化为自身
Map<CustomObject, CustomObject> parent = new HashMap<>();
for (CustomObject obj : list) {
    parent.put(obj, obj);
}

// 查找根节点(路径压缩优化)
private CustomObject find(CustomObject obj) {
    if (!parent.get(obj).equals(obj)) {
        parent.put(obj, find(parent.get(obj)));
    }
    return parent.get(obj);
}

// 合并两个对象所在的集合
private void union(CustomObject a, CustomObject b) {
    CustomObject rootA = find(a);
    CustomObject rootB = find(b);
    if (!rootA.equals(rootB)) {
        parent.put(rootB, rootA);
    }
}

// 第一步:将所有符合条件的对象合并到同一集合
for (int i = 0; i < list.size(); i++) {
    CustomObject obj1 = list.get(i);
    for (int j = i + 1; j < list.size(); j++) {
        CustomObject obj2 = list.get(j);
        // 同样可根据需求添加空字符串排除逻辑
        if (Objects.equals(obj1.getField1(), obj2.getField1()) 
            || Objects.equals(obj1.getField2(), obj2.getField2())) {
            union(obj1, obj2);
        }
    }
}

// 第二步:按根节点分组,每组内执行合并
Map<CustomObject, List<CustomObject>> groups = new HashMap<>();
for (CustomObject obj : list) {
    CustomObject root = find(obj);
    groups.computeIfAbsent(root, k -> new ArrayList<>()).add(obj);
}

// 第三步:合并每组内的对象
List<CustomObject> mergedList = new ArrayList<>();
for (List<CustomObject> group : groups.values()) {
    CustomObject result = group.get(0);
    for (int i = 1; i < group.size(); i++) {
        result = customMergeMethod(result, group.get(i));
    }
    mergedList.add(result);
}

适用场景

并查集通过路径压缩和合并优化,能将时间复杂度降低到接近O(n),非常适合处理十万级以上的大规模列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 17:15:27