距离上次发文,已经有一段时间了,最近工作比较忙,这不眼看快双十一了,就相当于给大家一些福利吧!
一、什么是数组去重
简单说就是把数组中重复的项删除掉,你 GET 到了吗 ?下面我将简单介绍下几种基本的方法及其优缺点。
二、方法汇总
- 两层循环
无相同值直接 push
进新数组,有相同的值则直接跳过本次内部循环
/*
* @param {Array} arr -要去重的数组
* @param {Array} result -初始化结果数组
*/
const unique = (arr, result = []) => {
const len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
// 相等则直接跳过
j = ++i;
}
}
result.push(arr[i]);
}
return result;
}
相同的做标记,与新数组作比较,没有则插入
/*
* @param {Array} arr -要去重的数组
* @param {Array} result -初始化结果数组
*/
const unique = (arr, result = []) => {
result.push(arr[0]);
const len = arr.length;
let rLen = result.length;
for (let i = 1; i < len; i++) {
let flag = false;
for (var j = 0; j < rLen; j++) {
if (arr[i] === result[j]) {
flag = true;
break;
}
}
if (!flag) {
rLen++;
result.push(arr[i]);
}
}
return result;
}
原地算法(在数组本身操作)
const unique = arr => {
const 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--;
}
}
}
return arr;
};
看似代码代码简单,实则内存占用高,不实用
- 单层循环
对象键不能重复
const unique = (arr, result = []) => {
const obj = {};
const len = arr.length;
for (let i = 0; i< len; i++) {
if (!obj[arr[i]]) {
// 键没有,则添加
obj[arr[i]] = 1;
result.push(arr[i]);
}
}
return result;
};
这种方法无法判断
'1'
和1
等类型,解决方案:
- 添加判断数据类型,比如
typeof
,obj[typeof arr[i] + arr[i]]
不过这还是判断不了['1']
和[1]
,因为这被相加后,结果都一样- 添加
JSON.stringify()
对结果进行去格式化,这时就可以判断了
排序后比较前后两位,不相等则添加进新数组
const unique = (arr, result = []) => {
arr.sort();
result.push(arr[0]);
const len = arr.length;
let rLen = result.length;
for (let i = 1; i < len; i++) {
if (arr[i] !== result[rLen - 1]) {
result.push(arr[i]);
rLen++;
}
}
return result;
}
方法比较直接
原地算法(排序后比较前后两位,相等则删除)
const unique = (arr) => {
arr.sort();
let len = arr.length;
for (let i = 1; i < len; i++) {
if (arr[i] === arr[i - 1]) {
arr.splice(i, 1)
len--;
}
}
return arr;
}
不消耗额外的空间
- 偷懒的节奏
indexOf
判断数组元素第一次出现的位置是否相同
const unique = (arr, result) => {
arr.forEach((item, index, array) => {
if(array.indexOf(item) === index) {
result.push(item);
}
});
return result;
}
// 使用ES6 filter
const unique = (arr) =>
arr.filter((item, index) => array.indexOf(item) === index);
使用ES6 方法更简洁性能更好
indexOf
的ES6 方法通过 includes
判断新数组中是否有该元素
const unique = (arr, result) => {
arr.forEach((item, index, array) => {
if(!result.includes(item)) {
// 或者 result.indexOf(item) === -1
result.push(item);
}
});
return result;
}
建议使用 includes
Map
数据结构,不懂 Map
的自行解决,传送门
const unique = arr => {
const map = new Map();
return arr.filter((item) => !map.has(item) && map.set(item, 1));
}
对象关系映射可以设置不同类型的键,使之很快能收集 arr
中不一样的数据
Set
数据结构,不允许出现重复数据,而且 Set
支持解构 传送门
const unique = arr => Array.from(new Set(arr));
// 或者通过 ES6 的 ...解构
const unique = arr => [...new Set(arr)];
简单粗暴
reduce
,给定初始值,根据数组循环给出最终值
const unique = (arr, result = []) => arr.reduce((prev,curr) => prev.includes(curr) ? prev : [...prev, curr], result);
三、总结
方法已经说了差不多了,就看你怎么用了,其中有一些差不多的方法,只是给了说明,没给具体的例子,希望大家自己去试一下,告辞!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。