
本文介绍一种简洁高效的 groovy 方式:通过 groupby + min 按自定义优先级(如 a1本文介绍一种简洁高效的 groovy 方式:通过 groupby + min 按自定义优先级(如 a1
在 Groovy 中处理结构化数据去重时,若需基于业务逻辑(而非字典序)判断“更优”元素(例如 A1 优于 A2),直接使用 Comparator 配合 removeAll 或 sort().unique() 往往冗余且易出错。更推荐采用函数式链式操作:先按关键字段(如 id)分组,再在每组内依据预设权重选取最优项。
核心思路是利用 groupBy 构建 Map
>,其中 key 是 id,value 是该 ID 对应的所有记录;随后用 collect 遍历每组,并调用 min { rank[it.type] } 获取 type 权重最小的元素。 以下为完整可运行示例:
def list = [ [id: 1, type: "A1", text: "Bla bla bla 1 - A1"], [id: 2, type: "A1", text: "Bla bla bla 2 - A1"], [id: 3, type: "A1", text: "Bla bla bla 3 - A1"], [id: 1, type: "A2", text: "Bla bla bla 1 - A2"] ] // 定义 type 的优先级映射(数值越小,优先级越高) Map rank = [A1: 1, A2: 2, R5: 3, R8: 4, A4: 5] // 分组 → 取每组中 rank[type] 最小的元素 List cleaned = list.groupBy { it.id } .collect { id, items -> items.min { rank.getOrDefault(it.type, Integer.MAX_VALUE) } } println cleaned // 输出:[[id:1, type:A1, text:Bla bla bla 1 - A1], [id:2, type:A1, text:Bla bla bla 2 - A1], [id:3, type:A1, text:Bla bla bla 3 - A1]]✅ 优势说明:
- 简洁安全:避免手动实现 Comparator 的空指针与类型转换风险(如原代码中 a.type 在 null 场景下会抛 NPE);
- 健壮扩展:getOrDefault(..., Integer.MAX_VALUE) 可兜底未定义的 type,防止运行时异常;
- 语义清晰:groupBy + min 直观表达“每组取最优”,符合 Groovy 函数式风格。
⚠️ 注意事项:
- 若原始列表为空,groupBy 返回空 Map,collect 仍安全执行,结果为空列表;
- 确保 rank 映射覆盖所有可能出现的 type 值,或始终使用 getOrDefault 防御性编程;
- 此方案默认返回新列表,不修改原数组——如需就地更新,可赋值回原变量:list = cleaned。
该方法同样适用于 Java(配合 Stream API 和自定义 Comparator),但在 Groovy 中凭借其动态语法和高阶集合操作,实现更精炼、可读性更强。










