详解js数组去重
js数组去重在前端面试中是经常被问道的问题,今天简单总结几种经典的数组去重方法以及一些大厂的面试题。
1、数组去重的常规方法
数组去重的常规思路总结如下:
- Set + ...\Array.form => 无法去掉{}
- 新数组 + indexOf方法 => 无法去掉NaN和{}
- 新数组 + includes方法 => 无法去掉{}
- filter + indexOf => 无法去掉{}, 两个NaN都会去掉, 不建议使用
- 双重for循环 + splice方法 => 无法去掉NaN和{}
- 新数组 + Map => 无法去掉{}
- 新数组 + 对象 => 所有的都能去重
- hasOwnProperty => 所有的都能去重
上述描述的测试数据:[1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]
数组去重的常规方法的代码如下:
// new Set + ...\Array.form
function arrFun(arr) {
return [...new Set(arr)];
// return Array.from(new Set(arr));
}
// indexOf or includes
function arrFun2(arr) {
const array = [];
// 或者下面if中的条件改为: !newArr.includes(item)
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i]);
}
return arr;
}
// filter + indexOf
function arrFun3(arr) {
return arr.filter((item, index, self) => {
return self.indexOf(item) === index;
});
}
// 两层循环 + splice
function arrFun5(arr) {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
len--; // 减少循环次数提高性能
j--; // 保证j的值自加后不变
}
}
}
return arr;
}
// Map
function arrFun6(arr) {
const map = new Map();
const newArr = [];
arr.forEach((item) => {
if (!map.has(item)) {
// has()用于判断map是否包为item的属性值
map.set(item, true); // 使用set()将item设置到map中,并设置其属性值为true
newArr.push(item);
}
});
return newArr;
}
// 对象
function arrFun7(arr) {
const newArr = [];
const obj = {};
arr.forEach((item) => {
if (!obj[item]) {
newArr.push(item);
obj[item] = true;
}
});
return newArr;
}
基于hasOwnProperty实现的数组去重如下:
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
2、数组去重进阶面试题
字节曾经有过这样一道面试题:{id: 1, name: 'admin'} 和 {id: 1, name: 'admin'} 应该是相同的(id、name都相同表明是同一个用户)请问这样的数据如何去重? 具体思路如下:
/**
* 数组去重
* 原始值使用严格相等比较, 对象值递归比较其所有属性, 属性数量和属性名称必须一致
* 数组中的对象均为plain object
* @param {Array} arr
* @return {Array}
*/
// 不使用任何标准库, 完全手写去重过程
function uniqueArray(arr){
let res = [];
for (let i = 0; i < arr.length; i++) {
let isFind = false;
for (let j = 0; j < res.length; j++){
// 下面的判断是自定义的判断, 通过该判断实现了题目的要求(原始值严格相等比较, 对象值递归比较)
if(equals(res[j], arr[i])){
isFind = true;
break;
}
}
if (!isFind) {
res.push(arr[i]);
}
}
return res;
}
function equals(v1, v2) {
return JSON.stringify(v1) === JSON.stringify(v2);
}
console.log(uniqueArray([1, 2, 2, 2, 3])); // [ 1, 2, 3 ]
console.log(uniqueArray([{id: 1, name: 'admin'}, {id: 1, name: 'admin'}])) // [ { id: 1, name: 'admin' } ]