如何基于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
相关产品推荐
相关产品推荐

