
本文介绍一种内存友好、时间复杂度为o(n)的java方案,使用hashmap按id索引并聚合多个sheet中的data对象,自动汇总amount1/amount2/amount3字段,确保所有id不丢失。
在实际业务场景(如Excel多表合并、报表聚合、ETL预处理)中,我们常需将多个来源的结构化数据(如不同Sheet)按唯一标识(如id)进行横向合并,并对数值字段做累加(sum)。若采用嵌套循环逐个查找匹配ID,时间复杂度将升至O(n²),且易遗漏或重复。更优解是利用哈希表实现单次遍历聚合——即以id为键构建累加缓存,边读边合并。
以下为推荐实现(已适配Lombok注解,兼容@Data和构造器):
import java.util.*;
public class DataMerger {
public static List mergeSheetsBySum(Map> sheetMap) {
// 使用 ID 作为 key,避免重复创建对象;value 存储当前累计的 Data 实例
Map accumulator = new HashMap<>();
// 遍历每个 Sheet(如 "sheet1", "sheet2", "sheet3")
for (List dataList : sheetMap.values()) {
for (Data data : dataList) {
int id = data.getId();
if (accumulator.containsKey(id)) {
// 已存在:累加各 amount 字段
Data existing = accumulator.get(id);
existing.setAmount1(existing.getAmount1() + data.getAmount1());
existing.setAmount2(existing.getAmount2() + data.getAmount2());
existing.setAmount3(existing.getAmount3() + data.getAmount3());
} else {
// 首次出现:深拷贝(避免引用原对象导致副作用)
accumulator.put(id, Data.builder()
.id(data.getId())
.amount1(data.getAmount1())
.amount2(data.getAmount2())
.amount3(data.getAmount3())
.build());
}
}
}
// 转为 List 并返回(顺序不保证,如需有序可转为 TreeMap 或后续排序)
return new ArrayList<>(accumulator.values());
}
} ✅ 关键优化点说明:
- 时间效率:仅需一次全量遍历(O(N),N为所有Sheet中Data总数),远优于暴力搜索的O(N×M);
- 内存安全:使用builder()或显式构造新实例,避免修改原始Data对象(尤其当原始列表被复用时);
- ID完整性:HashMap天然去重+覆盖逻辑,确保任意Sheet中出现的ID均被保留,无遗漏;
- 扩展友好:若后续增加amount4等字段,只需在累加块中补充一行,无需重构主干逻辑。
⚠️ 注意事项:
立即学习“Java免费学习笔记(深入)”;
- 若原始Data类未提供Builder或不可变构造器,建议优先补全@Builder或添加带参构造函数;
- 如需结果按ID升序排列,可在返回前添加:
return accumulator.values().stream() .sorted(Comparator.comparingInt(Data::getId)) .collect(Collectors.toList()); - 对于超大数据集(百万级),可考虑ConcurrentHashMap配合并行流(但需注意累加操作的线程安全性,此处简单累加可用compute()方法替代if-else)。
综上,该方案兼顾简洁性、性能与健壮性,是Java中跨数据源ID级聚合的工业级实践范式。










