JavaScript数组去重全攻略:从基础到封装
本文系统总结了JavaScript中实现数组去重的多种方案,涵盖双重循环、indexOf、sort排序、filter过滤以及Set/Map数据结构等常用技巧。文章进一步演示如何结合排序状态与回调函数,封装一个高复用性的通用去重API,适用于不同业务场景下的数据处理需求。
前言
在面试场景中,面试官常会要求对给定数组进行去重处理。除了使用Set这一常见手段外,你是否还能列举其他实现方式?能否独立封装一个具备复用价值的去重接口?回顾过往经历,面对此类问题时,往往难以迅速给出多种解决方案。本文将梳理针对该经典面试题的各种可行解法。
数组去重
1. 不使用数组API方法
首先介绍一种不依赖数组内置API的实现思路,具体代码实现如下:
var array = ['1', 1, '1', '1', '2', 2]
function unique(array) {
let res = []
for(let i = 0; i < array.length; i++){
for( var j = 0; j < res.length; j++){
if(array[i] === res[j]){
break;
}
}
if(j === res.length){
res.push(array[i])
}
}
return res
}
console.log(unique(array)); // [ '1', 1, '2', 2 ]既然避免使用数组原生API,核心思路便转向双重for循环。参考上述代码逻辑:
- 初始化一个用于存储结果的空数组。
- 遍历需要去重的原始数组。
- 在遍历过程中嵌套另一层循环,通过比对索引判断当前元素是否已存在于结果数组中。
调用该方法并输出结果,如代码注释所示,成功实现了数组去重功能。
2. 使用 indexOf
既然存在不使用API的方案,自然也有利用数组API的实现方式。下面展示如何利用indexOf完成去重,代码如下:
var array = ['1', 1, '1', '1', '2', 2]
function unique(array) {
let res = []
for (let i = 0; i < array.length; i++) {
if (res.indexOf(array[i]) === -1) { // 返回找到的第一个值得下标
res.push(array[i])
}
}
return res
}
console.log(unique(array))// [ '1', 1, '2', 2 ]如上述代码所示,巧妙利用indexOf检测结果数组中是否已包含当前元素。若未找到(返回-1),则将其加入结果数组,从而完成去重。
在上述代码基础上,可进一步优化,将for循环内的逻辑调整为:
if (array.indexOf((array[i])) == array.lastIndexOf(array[i])) {
i++
} else {
array.splice(array.lastIndexOf(array[i]), 1)
}无需引入额外变量,直接通过indexOf与lastIndexOf判断该值在原数组中是否为唯一存在。若是,则保留;否则从原数组中移除重复项,直接修改原数组实现去重。
3. 使用 sort
除了通过索引比对重复项,另一种思路是先对数组排序,再比较相邻元素是否相同。具体代码如下:
var array = [1, 3, 5, 4, 2, 1, 2, 4, 4, 4]
function unique(array) {
let res = []
let sortedArray = array.concat().sort() //concat() 返回新的数组
let seen;
for (let i = 0; i < sortedArray.length; i++) {
if (!i || seen !== sortedArray[i]) {
res.push(sortedArray[i])
}
seen = sortedArray[i]
}
return res
}
console.log(unique(array)); // [ 1, 2, 3, 4, 5 ]如上述代码,首先获取排序后的新数组,随后遍历该数组。通过维护一个记录前一个值的变量seen,判断其与当前值是否一致,从而筛选出唯一值。
注意:由于数组排序方法无法区分数字与字符串类型,使用此方法前需确保数组内元素类型一致,否则可能导致非预期结果。
4. 使用 filter
既然涉及排序,直接使用ES6新增的filter过滤器API也是合理选择,代码如下:
var array = ['1', 1, '1', '1', '2', 2]
function unique(array) {
let res = array.filter((item, index, array) => {
return array.indexOf(item) === index
})
return res
}
console.log(unique(array)); // [ '1', 1, '2', 2 ]如上述代码,filter直接利用array.indexOf(item) === index作为过滤条件,返回一个新数组,从而实现去重。
结合上述代码,若将indexOf作为过滤条件,也可进一步结合sort方法,仅用一行代码解决去重问题。代码如下:
function unique(array) {
return array.concat().sort().filter((item, index, array) => !index || item !== array[item - 1])
}
console.log(unique(array)); // [ '1', 1, '2', 2 ]5. 使用Set、Map、或者对象
除上述基于数组API和非API的方法外,借助对象结构也是常见思路。使用Set数据结构是最直观的选择;Map与对象方法类似,均以数组元素作为键(key),最后将所有值提取组成新数组。此处不再赘述代码,感兴趣者可自行实践。
(针对对象key仅支持字符串的问题,可转换思路:将索引作为key,元素值作为value,通过判断不同key对应的值是否相同来实现去重。此外,在存储key时可附加类型信息并进行类型转换处理。)
自己封装一个去重API
介绍完上述各类去重方法后,接下来总结并融合成一个具备高复用性、能适配不同场景的通用API。
以下介绍我封装的一个数组去重API实现:
- 该方法接收三个参数:第一个为待去重的数组;第二个标识该数组是否已排序;第三个为回调函数。
- 该回调函数同样接收三个参数:当前值、索引以及原数组。其作用允许用户对数组进行额外处理(例如将字符串统一转为小写)。
- 第二、三个参数为可选,可不传递。
var array = [1, 2, '1', 'a', 'A', 2, 1]
var array2 = [1, 1, '1', 2, 2]
function uniq(array, isSorted, iteratee) {
let seen = []
let res = []
for(let i = 0; i < array.length; i++){
let computed = iteratee ? iteratee(array[i], i,array) : array[i]
if(isSorted) {
if(!i || seen !== array[i]){
res.push(array[i])
}
seen = array[i]
}else if(iteratee) {
if(seen.indexOf(computed) === -1){
seen.push(computed)
res.push(computed)
}
}
else {
if(res.indexOf(array[i]) === -1) {
res.push(array[i])
}
}
}
return res
}
let result = uniq(array, false, function(item, index, arr){
return typeof item == 'string' ? item.toLowerCase() : item
})
console.log(result); // [ 1, 2, '1', 'a' ]
console.log(uniq(array2, true)); // [ 1, 2 ]总结
关于数组去重,若在面试中能列举出上述多种方法,通常即可通过考核。尽管题目本身难度不高,但要熟练掌握并灵活运用多种方案,仍需具备扎实的知识储备。
以上就是JavaScript中数组去重的办法总结的详细内容,更多关于JavaScript数组去重的资料请关注本站其它相关文章!
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
相关标签:
