js如何合并两个数组去重

js如何合并两个数组去重
最新回答
你长了一张欠吻的嘴

2022-08-13 09:38:00

在JavaScript中合并两个数组并去除重复项,可根据数组元素类型选择不同方法,以下是具体方案:

原始类型数组(数字、字符串、布尔值、null、undefined、NaN)

使用 Set 结合展开运算符 是最简洁高效的方式,Set 会自动处理唯一性,包括将 NaN 视为单一值。

function mergeAndDeduplicateArrays(arr1, arr2) { return [...new Set([...arr1, ...arr2])];}// 示例const arrayA = [1, 2, 3, 4, 'a', 'b', null, undefined];const arrayB = [3, 4, 5, 6, 'b', 'c', null, undefined, NaN];const result = mergeAndDeduplicateArrays(arrayA, arrayB);console.log(result); // 输出:[1, 2, 3, 4, 'a', 'b', null, undefined, 5, 6, 'c', NaN]

优势

  • 内置去重能力:Set 自动检查元素是否重复,无需手动编写循环和条件判断。
  • 性能高效:查找和插入操作平均时间复杂度接近 O(1),远优于传统循环嵌套 indexOf 的 O(n²)。
  • 特殊值处理:NaN 在 Set 中被视为唯一值,避免重复添加。
对象数组

Set 基于引用判断对象相等,即使两个对象属性相同,只要引用不同也会被视为不同。此时需采用以下方法:

1. 基于唯一 ID 的 Map 去重法(推荐)

遍历合并后的数组,以对象唯一标识符(如 id)为键存入 Map,后出现的同 ID 对象会覆盖前者,最后转回数组。

function mergeAndDeduplicateObjectsById(arr1, arr2) { const combined = [...arr1, ...arr2]; const uniqueMap = new Map(); for (const item of combined) { if (item && item.id !== undefined) { uniqueMap.set(item.id, item); } } return Array.from(uniqueMap.values());}// 示例const arrObj1 = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}];const arrObj2 = [{id: 2, name: 'Robert'}, {id: 3, name: 'Charlie'}];const resultObj = mergeAndDeduplicateObjectsById(arrObj1, arrObj2);console.log(resultObj);// 输出:[{id: 1, name: 'Alice'}, {id: 2, name: 'Robert'}, {id: 3, name: 'Charlie'}]

优势

  • 高效性:Map 的 set 和 get 操作平均时间复杂度接近 O(1)。
  • 灵活性:可根据业务逻辑决定保留哪个同 ID 对象(如后者覆盖前者)。
2. JSON.stringify 序列化去重法(适用场景有限)

将对象序列化为字符串后用 Set 去重,但受限于属性顺序、不可序列化值(如函数、undefined)及循环引用问题。

function mergeAndDeduplicateObjectsByStringify(arr1, arr2) { const combined = [...arr1, ...arr2]; const uniqueStrings = new Set(); const uniqueObjects = []; for (const item of combined) { try { const itemString = JSON.stringify(item); if (!uniqueStrings.has(itemString)) { uniqueStrings.add(itemString); uniqueObjects.push(item); } } catch (e) { console.warn("无法序列化对象,跳过:", item, e); } } return uniqueObjects;}// 示例const arrObj3 = [{a:1, b:2}, {b:2, a:1}, {c:3}];const arrObj4 = [{a:1, b:2}, {d:4}];const resultStr = mergeAndDeduplicateObjectsByStringify(arrObj3, arrObj4);console.log(resultStr);// 输出:[{a:1, b:2}, {c:3}, {d:4}](注意属性顺序敏感问题)

局限性

  • 属性顺序敏感:{a:1, b:2} 和 {b:2, a:1} 会被视为不同字符串。
  • 不可序列化值:无法处理函数、undefined 等非 JSON 值。
  • 循环引用:会抛出错误。
性能优化策略
  1. 选择正确算法

    原始类型优先用 Set,对象类型优先基于唯一 ID 使用 Map。

    避免循环嵌套 indexOf 或 includes,其时间复杂度为 O(n²)。

  2. 避免冗余操作

    若数据来源已保证唯一性,无需去重。

    大数据量时考虑增量更新,仅处理新增或变化部分。

  3. 优化数据结构

    在后端或数据源层面保证数据唯一性。

    为对象定义明确且易于访问的唯一 ID。

  4. 分析性能瓶颈

    使用浏览器开发者工具(如 Chrome DevTools 的 Performance 面板)定位耗时操作。

总结
  • 原始类型数组:直接使用 [...new Set([...arr1, ...arr2])],简洁高效。
  • 对象数组:优先基于唯一 ID 使用 Map 去重,避免直接使用 Set。
  • 性能关键:选择 O(n) 时间复杂度的算法,避免冗余操作,合理设计数据结构。