
本文介绍使用 javascript es6 的 reduce + object.values + filter + flat 方法,基于多个指定字段(如 itemid、nbr、recordid)识别并完整提取所有重复对象,不修改原始结构,仅返回原始数组中真实存在的重复副本。
本文介绍使用 javascript es6 的 reduce + object.values + filter + flat 方法,基于多个指定字段(如 itemid、nbr、recordid)识别并完整提取所有重复对象,不修改原始结构,仅返回原始数组中真实存在的重复副本。
在实际开发中,我们常需从对象数组中筛选出“逻辑重复”——即某些关键字段(非全部)完全一致的多个对象,且要求原样保留所有重复项(而非去重或取唯一代表)。例如,业务中可能将 itemId、nbr 和 recordID 视为联合业务主键,当三者同时相同时即视为数据异常重复,需批量提取用于校验或修复。
核心思路是:构建复合键 → 分组归集 → 筛选多元素组 → 展平结果。以下为推荐实现:
const items = [
{id: 'uuid-uuu', itemId: 110, nbr: 135, recordID: 222},
{id: 'uuid-www', itemId: 111, nbr: 134, recordID: 555},
{id: 'uuid-xxx', itemId: 111, nbr: 134, recordID: 555},
{id: 'uuid-yyy', itemId: 111, nbr: 134, recordID: 111},
{id: 'uuid-zzz', itemId: 112, nbr: 135, recordID: 222},
];
const duplicateItems = Object.values(
items.reduce((acc, item) => {
const { itemId, nbr, recordID } = item;
const key = `${itemId}|${nbr}|${recordID}`; // 使用 | 分隔更安全(避免数字拼接歧义,如 1+11 vs 11+1)
acc[key] ??= [];
acc[key].push(item);
return acc;
}, {})
).filter(group => group.length > 1)
.flat();
console.log(duplicateItems);
// 输出:
// [
// {id: 'uuid-www', itemId: 111, nbr: 134, recordID: 555},
// {id: 'uuid-xxx', itemId: 111, nbr: 134, recordID: 555}
// ]✅ 关键设计说明:
- 使用模板字符串生成复合键(推荐用 | 或其他非常见分隔符,避免 110+135+222 与 11+0135+222 等潜在冲突);
- acc[key] ??= [] 是空值合并赋值,简洁替代 if (!acc[key]) acc[key] = [];
- Object.values() 提取所有分组数组,filter(... > 1) 精准保留含重复项的组,flat() 将二维结构展平为一维结果数组;
- 原始对象引用被完整保留,无深拷贝开销,也未修改输入数组。
⚠️ 注意事项:
- 若字段值可能为 null/undefined/NaN,建议先做标准化处理(如 .toString() 或提供默认值),否则会影响键一致性;
- 对超大数组(>10 万项),可考虑使用 Map 替代普通对象以提升键查找性能(Map 对复杂键更友好,但此处字符串键差异不大);
- 此方案不依赖外部库,兼容现代浏览器及 Node.js ≥ 12。
该方法兼顾可读性、性能与健壮性,是处理多字段联合重复检测的推荐实践。

















