如何高效深度对比数组内对象并找出完全重复项?
数组深度对比查找完全重复对象的高效方案
针对你提到的数百个对象的场景,哈希法是可靠且性能最优的选择,同时也有其他可行方案,以下是具体分析和实现:
哈希对比法(首推)
可靠性说明
只要保证对象序列化的稳定性(相同结构和值的对象生成完全一致的字符串),哈希法可以100%准确识别重复对象——SHA-1/MD5等算法的碰撞概率极低,完全可以忽略普通业务场景下的碰撞风险。如果极端担心碰撞,可以在哈希冲突时额外用深度对比做校验(几乎不会触发)。
实现步骤
生成稳定序列化字符串
原生JSON.stringify不保证对象键的顺序,会导致相同对象生成不同字符串,所以需要用排序键的序列化逻辑:function stableStringify(obj) { if (typeof obj !== 'object' || obj === null) return JSON.stringify(obj); if (Array.isArray(obj)) return `[${obj.map(stableStringify).join(',')}]`; const sortedKeys = Object.keys(obj).sort(); return `{${sortedKeys.map(k => `"${k}":${stableStringify(obj[k])}`).join(',')}}`; }也可以用更高效的成熟库如
fast-json-stable-stringify,减少自己维护代码的成本。生成哈希并统计重复项
用序列化字符串生成哈希,再通过Map快速统计重复:// Node.js环境用crypto模块,浏览器可引入如js-sha1等库 const { createHash } = require('crypto'); function getHash(str) { return createHash('sha1').update(str).digest('hex'); } function findDuplicates(arr) { const hashMap = new Map(); const duplicates = []; for (const obj of arr) { const str = stableStringify(obj); const hash = getHash(str); if (hashMap.has(hash)) { // 首次发现重复时加入原对象,后续直接加入当前对象 if (!hashMap.get(hash).added) { duplicates.push(hashMap.get(hash).obj); hashMap.get(hash).added = true; } duplicates.push(obj); } else { hashMap.set(hash, { obj, added: false }); } } return duplicates; }
优缺点
- 优势:时间复杂度O(n),数百个对象处理耗时可以忽略;逻辑清晰,扩展性强。
- 劣势:无法直接处理循环引用的对象,需要额外添加循环引用检测逻辑;依赖序列化的稳定性。
优化版双层循环+深度对比
如果不想用哈希/序列化,针对数百个对象的规模,优化后的双层循环也能满足需求,但性能远不如哈希法:
实现代码
const _ = require('lodash'); function findDuplicates(arr) { const duplicates = []; const checked = new Array(arr.length).fill(false); for (let i = 0; i < arr.length; i++) { if (checked[i]) continue; let hasDuplicate = false; for (let j = i + 1; j < arr.length; j++) { if (checked[j]) continue; if (_.isEqual(arr[i], arr[j])) { if (!hasDuplicate) { duplicates.push(arr[i]); hasDuplicate = true; } duplicates.push(arr[j]); checked[j] = true; } } if (hasDuplicate) checked[i] = true; } return duplicates; }
优缺点
- 优势:无需处理序列化逻辑,天然支持循环引用的对象;逻辑简单易懂。
- 劣势:时间复杂度O(n²),当对象数量超过1000时性能会明显下降。
其他方案(不推荐)
原生Set基于浅对比,无法直接用于对象深度去重;若要适配,需重写对象toString或使用第三方库,本质和哈希法类似,没有性能或易用性优势,不建议优先选择。
内容的提问来源于stack exchange,提问作者Filip
相关产品推荐
相关产品推荐

