0

0

js如何合并两个数组去重

煙雲

煙雲

发布时间:2025-08-12 10:09:01

|

613人浏览过

|

来源于php中文网

原创

在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)的平均时间复杂度。

    A+响应式布局后台模板
    A+响应式布局后台模板

    A+是一个完全响应式,基于Bootstrap3.3.7最新版本开发的扁平化主题,她采用了主流的左右两栏式布局,使用了Html5+CSS3等现代技术,她提供了诸多的强大的可以重新组合的UI组件,并集成了最新的jQuery版本(v2.1.1),当然,也集成了很多功能强大,用途广泛的jQuery插件,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对

    下载
  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获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

536

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

372

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

706

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

470

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

989

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

652

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

535

2023.09.20

苹果官网入口直接访问
苹果官网入口直接访问

苹果官网直接访问入口是https://www.apple.com/cn/,该页面具备0.8秒首屏渲染、HTTP/3与Brotli加速、WebP+AVIF双格式图片、免登录浏览全参数等特性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

10

2025.12.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
如何进行WebSocket调试
如何进行WebSocket调试

共1课时 | 0.1万人学习

TypeScript全面解读课程
TypeScript全面解读课程

共26课时 | 4.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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