首页 > web前端 > js教程 > 正文

js如何合并两个数组去重

煙雲
发布: 2025-08-12 10:09:01
原创
586人浏览过

在javascript中合并两个数组并去除重复项,最简洁高效的方法是使用set结合展开运算符。1. 对于原始类型值,直接使用[...new set([...arr1, ...arr2])]即可完成合并与去重,set会自动处理唯一性,包括将nan视为单一值;2. 对于对象数组,因set基于引用判断相等,需采用基于唯一id的map去重法:遍历合并后的数组,以对象id为键存入map,后出现的同id对象会覆盖前者,最后转回数组;3. 也可尝试json.stringify序列化对象后用set去重,但该方法受限于属性顺序、不可序列化值(如函数、undefined)及循环引用问题,适用场景有限;4. 性能上,set和map方案平均时间复杂度为o(n),远优于循环嵌套indexof的o(n²),优化关键在于选择合适算法:原始类型用set,对象类型优先基于唯一id使用map,并避免对无重复数据做冗余去重操作。该策略兼顾效率、可读性与实用性,是处理数组合并去重的推荐方案。

js如何合并两个数组去重

在JavaScript中合并两个数组并去除重复项,通常最简洁且高效的方法是利用

Set
登录后复制
数据结构的特性,结合展开运算符(
...
登录后复制
)来完成。这不仅能快速合并,还能自动处理原始类型值的去重。

js如何合并两个数组去重

合并和去重数组,我通常会倾向于使用

Set
登录后复制
。它提供了一种非常直观且性能不错的方案。

function mergeAndDeduplicateArrays(arr1, arr2) {
  // 使用展开运算符合并数组,然后通过Set自动去重
  const combinedSet = new Set([...arr1, ...arr2]);
  // 将Set转换回数组
  return Array.from(combinedSet);
  // 或者更简洁地: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]; // NaN会被视为一个,但两个NaN是不同的

const result = mergeAndDeduplicateArrays(arrayA, arrayB);
console.log(result); // [1, 2, 3, 4, 'a', 'b', null, undefined, 5, 6, 'c', NaN]
登录后复制

这个方法对于数字、字符串、布尔值、

null
登录后复制
undefined
登录后复制
等原始类型表现完美。
Set
登录后复制
内部会确保每个值都是唯一的,
NaN
登录后复制
虽然不等于自身,但在
Set
登录后复制
中会被视为唯一的一个值。

js如何合并两个数组去重

为什么Set是处理数组去重合并的优选方案?

在我看来,

Set
登录后复制
之所以成为JavaScript中处理数组去重合并的首选,主要在于其设计哲学与实际效率。它就是为了存储不重复的值而生的,这与我们的需求完美契合。

首先,

Set
登录后复制
内置去重能力是其最大的优势。当你向一个
Set
登录后复制
添加元素时,它会自动检查该元素是否已经存在。如果存在,就不会重复添加;如果不存在,则会加入。这种机制省去了我们手动编写复杂的循环和条件判断来检查重复项的麻烦,代码自然就更简洁、更易读。

js如何合并两个数组去重

其次,从性能角度看,

Set
登录后复制
的查找和插入操作通常具有接近O(1)的平均时间复杂度(虽然在最坏情况下可能退化,但对于大多数实际场景,其性能表现都非常出色)。这意味着无论数组有多大,处理原始类型时,
Set
登录后复制
都能提供相当快的去重速度。相比之下,如果采用传统的手动遍历加
indexOf
登录后复制
includes
登录后复制
去重,时间复杂度可能达到O(n^2),在大数据量面前会显得非常慢。

再者,

Set
登录后复制
在处理
NaN
登录后复制
undefined
登录后复制
等特殊值时,行为也符合直觉。
NaN
登录后复制
在JavaScript中是一个很特别的值,它不等于自身。但
Set
登录后复制
在处理
NaN
登录后复制
时,会将其视为一个唯一的元素。比如,你往
Set
登录后复制
里加两个
NaN
登录后复制
,最终
Set
登录后复制
里只会有一个
NaN
登录后复制
。这避免了一些潜在的陷阱。

总的来说,

Set
登录后复制
提供了一种声明式、高效且语义清晰的方式来解决数组合并去重的问题,让开发者可以把精力放在更核心的业务逻辑上,而不是纠结于去重的实现细节。

合并去重时,如何处理数组中包含对象的情况?

这是一个常见的“坑”,也是

Set
登录后复制
直接去重方案的局限性所在。当数组中包含对象时,
Set
登录后复制
的默认去重机制可能不会按照你预期的那样工作。因为
Set
登录后复制
使用严格相等(
===
登录后复制
来判断值的唯一性。对于对象来说,即使两个对象拥有完全相同的属性和值,只要它们在内存中是不同的引用,
Set
登录后复制
就会认为它们是两个不同的对象。

比如:

[{id: 1, name: 'A'}]
登录后复制
[{id: 1, name: 'A'}]
登录后复制
,这两个对象在
Set
登录后复制
看来是不同的。

要解决这个问题,我们需要引入一些自定义的逻辑,核心思路是:定义“重复”的标准。通常,我们会基于对象的一个或多个唯一属性(比如

id
登录后复制
uuid
登录后复制
key
登录后复制
等)来判断对象是否重复。

以下是几种处理策略:

  1. 基于唯一ID属性去重(推荐且常用) 这是最常见也最实用的方法。如果你的对象都有一个唯一的标识符(如

    id
    登录后复制
    ),你可以利用这个
    id
    登录后复制
    来判断对象是否重复。

    function mergeAndDeduplicateObjectsById(arr1, arr2) {
      const combined = [...arr1, ...arr2];
      const uniqueMap = new Map(); // 使用Map来存储唯一的对象,key为id
    
      for (const item of combined) {
        if (item && item.id !== undefined) { // 确保对象存在且有id属性
          // 如果Map中没有这个id,或者新对象的版本更“新”(根据业务逻辑决定)
          // 这里我们简单地以id为key存储,后来的同id对象会覆盖前面的
          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);
    // 结果可能取决于你希望保留哪个同ID对象,这里是后者覆盖前者
    console.log(resultObj);
    // 预期输出:[{id: 1, name: 'Alice'}, {id: 2, name: 'Robert'}, {id: 3, name: 'Charlie'}]
    登录后复制

    这种方法高效,因为

    Map
    登录后复制
    Set
    登录后复制
    get
    登录后复制
    操作也是接近O(1)的平均时间复杂度。

    降重鸟
    降重鸟

    要想效果好,就用降重鸟。AI改写智能降低AIGC率和重复率。

    降重鸟 113
    查看详情 降重鸟
  2. 将对象转换为字符串去重(适用于简单、可序列化对象) 如果你确定对象的所有属性都是可JSON序列化的,并且属性顺序不影响唯一性判断,可以考虑将对象

    JSON.stringify
    登录后复制
    成字符串,然后用
    Set
    登录后复制
    去重字符串。

    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}]; // 注意:JSON.stringify对属性顺序敏感
    const arrObj4 = [{a:1, b:2}, {d:4}];
    
    // 如果属性顺序不同,即使内容一样,也会被认为是不同的
    // [{a:1, b:2}] 和 [{b:2, a:1}] 可能会被认为是两个不同的字符串
    const resultStr = mergeAndDeduplicateObjectsByStringify(arrObj3, arrObj4);
    console.log(resultStr);
    登录后复制

    局限性:

    JSON.stringify
    登录后复制
    对属性的顺序是敏感的,
    {a:1, b:2}
    登录后复制
    {b:2, a:1}
    登录后复制
    会被序列化成不同的字符串。此外,它不能处理循环引用、函数、
    undefined
    登录后复制
    等非JSON值。因此,这种方法只适用于结构非常简单且可控的对象。

选择哪种方法,取决于你的具体业务场景和对象结构。通常,基于唯一ID属性的去重是最健壮和推荐的方案。

合并去重操作对性能有什么影响?我们应该如何优化?

合并和去重操作的性能影响,很大程度上取决于你选择的算法、数组的大小以及数组中元素的类型。理解这些影响,能帮助我们做出更明智的优化决策。

性能影响分析:

  1. 时间复杂度:

    • Set
      登录后复制
      方法(针对原始类型):
      通常是O(N),其中N是合并后数组的总元素数。这是因为
      Set
      登录后复制
      的插入和查找操作平均是常数时间。这是最理想的情况。
    • 基于
      Map
      登录后复制
      的ID去重(针对对象):
      同样接近O(N)。通过对象的唯一ID作为
      Map
      登录后复制
      的键,查找和插入效率很高。
    • 循环
      +
      登录后复制
      indexOf
      登录后复制
      /
      includes
      登录后复制
      这是效率最低的常见方法,时间复杂度为O(N^2)。每添加一个元素,都需要遍历已处理的部分来检查是否重复。当N很大时,性能会急剧下降。
    • JSON.stringify
      登录后复制
      Set
      登录后复制
      去重:
      涉及到字符串化(O(K) K为对象属性数)和字符串的哈希计算(可能与字符串长度有关),整体性能介于O(N)和O(N^2)之间,取决于对象的复杂度和数量。
  2. 内存占用

    • Set
      登录后复制
      Map
      登录后复制
      都需要额外的内存来存储其内部数据结构。对于非常大的数组,这可能会是一个考虑因素,但通常在现代浏览器环境中不是瓶颈。
    • JSON.stringify
      登录后复制
      会创建新的字符串副本,也增加了临时内存消耗。

优化策略:

  1. 选择正确的算法:

    • 优先使用
      Set
      登录后复制
      和展开运算符
      来处理包含原始类型(数字、字符串、布尔值等)的数组去重。这是最直接、最高效的方案。
    • 对于包含对象的数组,务必使用基于唯一标识符(如
      id
      登录后复制
      )的
      Map
      登录后复制
      或自定义遍历逻辑去重。
      避免直接将对象放入
      Set
      登录后复制
      ,因为它只会比较引用。
  2. 避免不必要的去重:

    • 如果数据来源本身就保证了唯一性,或者你只关心合并而不关心去重,那就不要进行去重操作。
    • 在某些场景下,如果数据量非常大且频繁进行合并去重,可以考虑增量更新。只对新增或变化的部分进行去重,而不是每次都处理整个数据集。
  3. 考虑数据结构的设计:

    • 在后端或数据源层面就保证数据的唯一性,减少前端去重的负担。例如,数据库查询结果就避免重复。
    • 如果对象去重是常见需求,确保你的对象有一个明确且易于访问的唯一ID。
  4. 性能瓶颈分析:

    • 对于性能敏感的应用,如果发现合并去重是瓶颈,可以使用浏览器开发者工具(如Chrome DevTools的Performance面板)进行剖析,找出具体是哪一步耗时最多。有时候,瓶颈可能不在去重本身,而在前置的数据处理或后置的DOM操作。

总的来说,对于JS数组的合并去重,我的经验是:对于原始类型,

Set
登录后复制
就是王者,直接用就好;对于对象,关键在于你如何定义“重复”,然后用
Map
登录后复制
或自定义遍历来高效实现这个定义。过早的微优化往往是浪费时间,但选择正确的、高效率的算法是基础。

以上就是js如何合并两个数组去重的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号