前端小技巧: 数组去重的15种方法

考虑计算效率的几种方法

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中的集合,是可以使用不同的数据类型的
    • 所以,需要注意上述方法中的一些适用场景
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值