js数组去重效率测试

最近一次面试遇到了一个问题,用原生js至少实现三种数思路,巴拉巴拉…,描述完毕.另一个问题又来了,请分析一下哪一种的效率最高,当时我就想,应该越是原生的代码,效率应该越高吧.然后就现实并非如此,面试自然也就无疾而终,然后我回家做了一番测试,结果如下

1 双层遍历
 default: 7.007080078125ms
2 排序去重
default: 43.743896484375ms
3 对象属性去重
default: 3.615966796875ms
4 indexOf去重
default: 8.56396484375ms
5 includes去重
default: 8.193115234375ms
6 filter过滤检测
default: 8.48291015625ms
7 forEach去重
default: 8.1611328125ms
8 lastIndexOf去重
default: 3.82177734375ms
9 set方法
default: 1.489990234375ms

下面是测试步骤

首先我创建了一个大数组

		const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;   
		const arr1 = Array.from(Array(10000), (v,k) => ({a: random(0, 10000)}));

网上找了一些方法 ,用了这位博主的 [https://www.jb51.net/article/121410.htm] 感谢

// Methods 1 双层遍历
	function unique(arr){
		var res = [arr[0]];
		for(var i=1; i<arr.length; i++){
			var repeat = false;
			for(var j=0; j<res.length; j++){
				if(arr[i] === res[j]){
					repeat = true;
					break;
				}
			}
			if(!repeat){
				res.push(arr[i]);
			}
		}
		return res;
	}
	
	// Methods 2 排序去重
	function unique2(arr){
		var arr2 = arr.sort();
		var res = [arr2[0]];
		for(var i=1; i<arr2.length; i++){
			if(arr2[i] !== res[res.length-1]){
				res.push(arr2[i]);
			}
		} 
		return res;
	}
	
	// Methods 3 对象属性去重
	function unique3(arr){
		var res = [];
		var obj = {};
		for(var i=0; i<arr.length; i++){
			if( !obj[arr[i]] ){
				obj[arr[i]] = 1;
				res.push(arr[i]);
			}
		} 
		return res;
	}
	
	// Methods 4 indexOf去重
	function unique4(arr){
		var res = [];
		for(var i=0; i<arr.length; i++){
			if(res.indexOf(arr[i]) == -1){
				res.push(arr[i]);
			}
		}
		return res;
	}
	
	// Methods 5 includes检测去重
	function unique5(arr){
		var res = [];

		for(var i=0; i<arr.length; i++){
			if( !res.includes(arr[i]) ){ // 如果res新数组包含当前循环item
				res.push(arr[i]);
			}
		}
		return res;
	}
	
	// Methods 6 filter过滤检测
	function unique6(arr){
		var res = [];

		res = arr.filter(function(item){
			return res.includes(item) ? '' : res.push(item);
		});
		return res;
	}

	// Methods 7 forEach去重
	function unique7(arr){
		var res = [];

		arr.forEach(function(item){
			res.includes(item) ? '' : res.push(item);
		}); 
		return res;
	}


	// Methods 8 lastIndexOf去重
	function unique8(arr){
		var res = []; 
		for(var i=0; i<arr.length; i++){
			res.lastIndexOf(arr[i]) !== -1 ? '' : res.push(arr[i]);
		}
		return res;
	}
	
	// Methods 9 Set去重
	function unique9(arr){
		return Array.from(new Set(arr));
	}

打印测试

	// 1 双层遍历
	console.log("1 双层遍历")
	console.time()
	unique(arr1)
	console.timeEnd();
	
	// 2 排序去重
	console.log("2 排序去重")
	console.time()
	unique2(arr1)
	console.timeEnd();
	
	// 3 对象属性去重
	console.log("3 对象属性去重")
	console.time()
	unique3(arr1)
	console.timeEnd();
	
	// 4 indexOf去重
	console.log("4 indexOf去重")
	console.time()
	unique4(arr1)
	console.timeEnd();
	
	// 5 includes去重
	console.log("5 includes去重")
	console.time()
	unique5(arr1)
	console.timeEnd();
	
	// 6 filter过滤检测
	console.log("6 filter过滤检测")
	console.time()
	unique6(arr1)
	console.timeEnd();
	
	// 7 forEach去重
	console.log("7 forEach去重")
	console.time()
	unique7(arr1)
	console.timeEnd();
	

	// 8 lastIndexOf去重
	console.log("8 lastIndexOf去重")
	console.time()
	unique8(arr1)
	console.timeEnd();
	
	// 9 set方法
	console.log(" 9 set方法")
	console.time()
	unique9(arr1)
	console.timeEnd();

结论:

由以上的结果我们可以知道,其实es6去重方法set()效率还是最高的,究其原因,大概是底层的c源码实现的缘故.所以在不考虑兼容的前提下,大家放心大胆的用new Set()方法就行了,假如需要考虑兼容问题,indexOf也是个不错的选择,此方法也是最常用最容易理解的。

2021年-6-25 结论修改:

new Set的效率在一万条数据的情况下,确实是最快的。但是当数据达到百万千万级别,for 循环 结合对象属性的唯一性来实现,效率则更高。研究了几个ES6的api效率的问题,包括 filterMapreduce等方法,它们在一万条数据计算的情况下,效率优于其他方案。同样,当数据量达到百万千万级别时,for循环的一些实现方案则效率更优。所以我们在做js优化的过程中,应该考虑对于不同的数据量选用不同的优化方案才能更好的做好优化。顺带提一句,indexOf在大量的数据处理过程中会极大的降低代码性能,所以在大量数据处理的代码中,我们应该避免使用它。

贴一下以上结论的部分测试代码,有兴趣的可自行编码测试

1万,100万,

	/**
	 * 研究数组对象去重的效率问题
	 * 对数组进行去重
	 */
	const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;   
 
	const list = Array.from(Array(10000), (v,k) => random(0, 100000 ));
	
	console.time("Set");
	let arr = Array.from(new Set(list));
	console.timeEnd("Set");

	
	console.time("for");
	let obj1 = {};
	let data1 = [];
	for(let i = 0, len = list.length; i < len; i++){
		const item = list[i];
		if( obj1[item] === undefined ){ 
			 obj1[item] = item;
			 data1.push(item);
		}
	}
	console.timeEnd("for");

测试结果

1万条数据

Set: 0.512939453125 ms
for: 4.902099609375 ms

100万条数据

Set: 30.05615234375 ms
for: 17.64111328125 ms
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值