考虑计算效率的几种方法
1 ) Array.from + Set 去重
function unique(arr) {
return Array.from(new Set(arr));
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
2 ) Set + rest参数 去重
function unique(arr) {
return [...new Set(arr)];
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
3 ) 传统去重: 循环 + indexOf
function unique(arr) {
const res = [];
arr.forEach(item => {
if (res.indexOf(item) < 0) res.push(item);
})
return res;
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
3 ) 传统去重: 循环 + indexOf + lastIndexOf
function unique(arr) {
const res = [];
arr.forEach(item => {
if (res.indexOf(item) < 0) res.push(item);
})
return res;
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
4 ) 传统去重: 循环 + includes
function unique(arr) {
const res = [];
arr.forEach(item => {
if (!res.includes(item)) res.push(item);
})
return res;
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
5 ) json对象去重
function unique(arr) {
const json = {};
const tmp = [];
arr.forEach(item => {
if (!json[item]) {
json[item] = 1; // 1 或 true
tmp.push(item);
}
});
return tmp;
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
6 ) map去重,思路同json对象去重
function unique(arr) {
const map = new Map();
const tmp = [];
arr.forEach(item => {
// 判断是否存在该key值, 当前值作为map的key值
if (!map.has(item)) {
map.set(item, 1); // 1 或 true
tmp.push(item);
}
});
return tmp;
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) // [30, 10, 20, 40]
7 ) 排序 + 循环 去重 (因为存在排序,结果可能会和其他去重方式得到的结果不一致,但去重效果一致)
function unique(arr) {
// 1. 先让arr有序
arr.sort();
// 2. 循环对比相邻元素,
const tmp = [];
arr.forEach((item, index) => {
// 备注:这里最后一次对比,会存在越界,但是越界不影响结果
if (item !== arr[index + 1]) tmp.push(item);
})
// 3. 返回最终结果
return tmp;
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [10, 20, 30, 40]
8 ) 排序 + 递归 去重 (因为存在排序,结果可能会和其他去重方式得到的结果不一致,但去重效果一致)
function unique(arr) {
// 1. 先让arr有序
arr.sort();
// 2. 递归移除相邻重复元素
(function recursionFn(index) {
if (index > arr.length - 2) return;
if (arr[index] === arr[index + 1]) arr.splice(index, 1);
recursionFn(index + 1);
})(0);
// 3. 返回最终结果
return arr;
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [10, 20, 30, 40]
9 ) reduce + includes 归并去重
function unique(arr) {
// 1. 定义归并方法
const reduceFn = (prevArr, cur) => {
if (prevArr.includes(cur)) {
return prevArr;
}
prevArr.push(cur);
return prevArr;
}
// 2. 进行归并处理
const tmp = [];
arr.reduce((prevArr, cur) => reduceFn (prevArr, cur), tmp);
// 3. 返回最终结果
return tmp;
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40]
10 ) reduce + indexOf 归并去重
function unique(arr) {
// 1. 定义归并方法
const reduceFn = (prevArr, cur) => {
if (prevArr.indexOf(cur) !== -1) {
return prevArr;
}
prevArr.push(cur);
return prevArr;
}
// 2. 进行归并处理
const tmp = [];
arr.reduce((prevArr, cur) => reduceFn (prevArr, cur), tmp);
// 3. 返回最终结果
return tmp;
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40]
11 ) filter + includes 去重
function unique(arr) {
let tmp = [];
return arr.filter(function(item, index) {
const isIn = tmp.includes(item);
if (!isIn) tmp.push(item);
return !isIn;
});
tmp = null; // 释放
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40];
- filter 过滤符合某一规则的集合
12 ) 循环 + indexOf + lastIndexOf 去重
function unique(arr) {
for(let i = 0; i < arr.length; i++) {
const current = arr[i];
const lastIndex = arr.lastIndexOf(current);
// 不管从前向后亦或是从后向前,索引一样才是唯一,不一样,则有重复,去除后面一项, i自减防止塌陷
if(i !== lastIndex) {
arr.splice(lastIndex, 1);
i --;
}
}
return arr;
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40];
13 ) filter + indexOf 去重 (循环 + indexOf,循环 + indexOf + lastIndexOf 和 filter + includes 的优化版)
function unique(arr) {
return arr.filter((item, index) => {
return arr.indexOf(item, 0) === index;
});
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40];
- 这种方式会跳过重复的元素
- 备注: indexOf 第二个参数默认为 0 (可选),范围在 0 ~ arr.length -1 之间
14 ) filter + hasOwnProperty 去重 (json对象去重的优化版)
function unique(arr) {
const obj = {};
return arr.filter(function(item, index) {
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
});
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40];
- 上述表达式:
obj[typeof item + item] = true
结果为 true- 如果这样写
obj[typeof item + item] = 1
结果为1 - 在 filter 中两者均可
- 如果这样写
typeof 1 + 1
值为: number1,通过数据类型和值来作为key- 注意,这里 直接调用对象的hasOwnProperty 这样用,可能在一些规范下报错,参考如下改写
const aa = {a: 222} Object.hasOwnProperty.call(aa, 'a') // true
效率较低的方法
1 )嵌套for循环
function unique(arr) {
for(let i=0; i<arr.length; i++) {
for(let j=i+1; j<arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1); // 如果有重复,移除后面的一项
j --; // 防止 arr 错位坍塌
}
}
}
return arr;
}
const res = unique([30, 10, 20, 30, 40, 10]);
console.log(res) // [30, 10, 20, 40];
- 这种嵌套循环的方式,每一轮循环找到唯一项,并删除可能的重复项
总结
- 去重,就是去除重复的选项,得到一组唯一的选项集合的过程
- 上述整理了15种去重方式,大同小异,只是实现方式上的区别
- 注意: 在前端或者说javascript中的集合,是可以使用不同的数据类型的
- 所以,需要注意上述方法中的一些适用场景