JS数组去重的三个高阶玩法

本文介绍了几种有效的数组去重方法,包括使用new Set(), Array.from() 和 Array的filter结合indexOf()等技术,帮助开发者轻松去除数组中的重复元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

…newSet()

对于基本数据类型的数组去重,可以使用 …new Set() 来过滤数组中重复的值,创建一个只有唯一值的新数组.在这里插入图片描述

Array.from(new Set())

在这里插入图片描述

Array的.filter及indexOf()

在这里插入图片描述
注意,indexOf()方法将返回数组中第一个出现的数组项.这就是为什么我们可以在每次迭代中将indexOf()方法返回的索引与当前索引进行比较,以确定当前项是否重复.

<think>好的,我现在需要帮助用户解决JavaScript数组的问题。用户已经提供了两个站内引用,分别是方法1(使用双层循环和splice)和方法2(使用filter和indexOf),但用户可能还想了解更多方法或者更优的解决方案。首先,我需要回顾用户提供的引用内容,确保正确理解他们的例子和可能的限制。 用户的问题是关于如何在JavaScript中实现数组。根据引用[1],方法1是通过双层循环比较元素,然后使用splice删除复项,但无法处理NaN的情况,因为NaN !== NaN。而引用[2]提到使用filter和indexOf,这种方法可以处理部分情况,但对于对象或NaN可能存在问题。 接下来,我需要考虑用户的实际需求。用户可能希望了解多种方法,包括处理NaN、对象等特殊情况的解决方案,以及不同方法的优缺点。此外,用户可能对ES6的新特性如Set和Map感兴趣,因为这些方法更简洁高效。 首先,我应该列举几种常见的方法,包括用户提到的两种,然后补充其他方法。例如,使用ES6的Set是最简单的方法,但无法处理对象和NaN的问题。不过,根据ES6的Set,实际上Set中的NaN会被视为相同的值,所以可以处理NaN。但用户引用的方法1中,双层循环无法处理NaN,因为使用的是===比较,而NaN !== NaN,导致无法。因此需要指出不同方法的差异。 然后,对于包含对象的数组,可以使用JSON.stringify,但这也有局限性,比如属性顺序不同或者包含不可序列化的值。另一种方法是使用Map来存储唯一标识,比如对象的某个属性,或者使用哈希函数。 另外,用户可能关心性能问题。双层循环的时间复杂度是O(n²),对于大数据量可能不够高效,而使用Set或Map的方法通常是O(n),更高效。因此需要比较不同方法的适用场景。 还需要注意特殊值如null、undefined、NaN的处理。例如,indexOf无法正确识别NaN,因为arr.indexOf(NaN)会返回-1,而includes方法可以检测NaN的存在。因此,使用includes的方法可能更可靠。 在整理这些方法时,需要给出代码示例,并说明每种方法的优缺点,以及适用场景。同时,需要指出哪些方法可以处理NaN和对象,哪些不能,帮助用户根据实际情况选择合适的方法。 最后,可能需要总结推荐方法,比如在支持ES6的环境下优先使用Set,对于复杂数据或需要自定义逻辑的情况使用Map或reduce方法。此外,提醒用户根据数据类型选择合适的方法,比如处理对象数组时需要考虑唯一性判断的标准。 总结步骤: 1. 介绍基本方法(双层循环、splice),指出其局限性(无法处理NaN)。 2. 使用filter和indexOf,说明其问题(无法处理NaN,对象)。 3. 引入ES6的Set,说明其简洁性和处理NaN的能力。 4. 使用includes方法改进filter方法,正确处理NaN。 5. 使用reduce方法,灵活处理。 6. 处理对象数组,使用Map或JSON.stringify,指出注意事项。 7. 对比各方法优缺点,给出推荐使用场景。 在回答时,需要结构清晰,分点说明,代码示例正确,并确保覆盖用户可能关心的各种情况,如性能、特殊值处理、对象等。</think>### JavaScript数组方法详解(7种方案) #### 一、基础循环法(适合所有数据类型) ```javascript function uniqueBasic(arr) { const result = [] for (let i = 0; i < arr.length; i++) { if (!result.includes(arr[i])) { // 使用includes可检测NaN[^1] result.push(arr[i]) } } return result } // 测试样例 console.log(uniqueBasic([1, 2, 2, NaN, NaN])) // [1, 2, NaN] ``` #### 二、双层循环+splice(原始方法) ```javascript function uniqueSplice(arr) { for (let i = 0; i < arr.length; i++) { for (let j = i + 1; j < arr.length; j++) { if (Object.is(arr[i], arr[j])) { // 使用Object.is可处理NaN[^1] arr.splice(j, 1) j-- } } } return arr } // 测试样例 console.log(uniqueSplice([NaN, NaN, 1, 1])) // [NaN, 1] ``` #### 三、filter+indexOf(ES5常用) ```javascript function uniqueFilter(arr) { return arr.filter((item, index) => arr.indexOf(item) === index // 缺陷:无法识别NaN[^1] ) } // 测试样例 console.log(uniqueFilter([1, 1, NaN, NaN])) // [1, NaN] ``` #### 四、Set数据结构(ES6推荐方案) ```javascript const uniqueSet = arr => [...new Set(arr)] // 测试样例 console.log(uniqueSet([1, 1, '1', NaN, NaN])) // [1, '1', NaN][^1] ``` #### 五、对象键值法(优化版) ```javascript function uniqueKey(arr) { const obj = Object.create(null) return arr.filter(item => { const key = typeof item + (typeof item === 'object' ? JSON.stringify(item) : item) return obj.hasOwnProperty(key) ? false : (obj[key] = true) }) } // 测试对象 console.log(uniqueKey([{a:1}, {a:1}, [1], [1]])) // [{a:1}, [1]] ``` #### 六、Map数据结构(处理复杂类型) ```javascript function uniqueMap(arr) { const map = new Map() return arr.filter(item => !map.has(item) && map.set(item, true) ) } // 测试样例 const obj = {name: 'test'} console.log(uniqueMap([obj, obj, {}, {}])) // [obj, {}, {}] ``` #### 七、reduce高阶函数(函数式编程) ```javascript const uniqueReduce = arr => arr.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], [] ) // 测试样例 console.log(uniqueReduce([1, 2, 2, 3])) // [1, 2, 3] ``` --- ### 方法对比与选型建议 | 方法 | 时间复杂度 | 处理NaN | 处理对象 | 适用场景 | |-----------------|------------|---------|----------|---------------------| | Set法 | O(n) | ✅ | ❌ | 简单数据快速 | | Map法 | O(n) | ✅ | ✅ | 包含对象的复杂数据 | | 对象键值法 | O(n) | ✅ | ✅ | 需要严格类型判断 | | filter+indexOf | O(n²) | ❌ | ❌ | ES5环境基础 | --- ### 特殊场景处理技巧 1. **混合类型** 使用`typeof`+值组合键: ```javascript function uniqueType(arr) { const seen = new Map() return arr.filter(item => { const key = typeof item + JSON.stringify(item) return seen.has(key) ? false : seen.set(key, true) }) } ``` 2. **对象数组** 指定唯一标识字段: ```javascript function uniqueByKey(arr, key) { return [...new Map(arr.map(item => [item[key], item])).values()] } // 示例:根据id const users = [{id:1}, {id:1}, {id:2}] console.log(uniqueByKey(users, 'id')) // [{id:1}, {id:2}] ``` 3. **大数据量优化** 使用空间换时间的哈希算法: ```javascript function uniqueHash(arr) { const hash = new Set() const result = [] arr.forEach(item => { if (!hash.has(item)) { hash.add(item) result.push(item) } }) return result } ``` --- ### 相关问题 1. 如何实现不区分大小写的字符串数组? 2. 针对10万条数据的数组,哪种方法性能最优? 3. 如何保留数组中的最后出现元素而非第一个? [^1]: ES6的Set数据结构将NaN视为相同值,而普通相等比较中NaN !== NaN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值