javascript
数组
array
去重
distinct
unique
刚好前天面试的时候面试官问到了数组去重的问题,当时有点语塞只想到用了两个循环检测(其实模模糊糊想到了hash的方法做但是由于记得不清不敢说= =!),思路是检测是否有元素重复,然后将只出现一次的元素推入到新数组中,然后返回新数组。然后面试官又问这种方法的时间效率,于是黑线了。so这两天看了一下相关的文章,在这里也总结一下javascript数组去重的方法。
两层循环检测重复元素法
首先,介绍一下大家都会想到的两层循环的demo,如下例:
function distinct(arr) {
var ret = [],
length = arr.length;
for(var i = 0;i < length; i++){
for(j = i+1; j<length;j++){
if(arr[i] === arr[j]){
j = ++i;
}
}
ret.push(arr[i]);
}
return ret;
}
var arra = [1,2,3,4,4,1,1,2,1,1,1];
distinct(arra); //返回[3,4,2,1]
<!--more-->
如上的代码实现是轻松易得的,思路如下:
首先外层循环比遍历整个数组
-
内层循环匹配是否有值重复
a.如判断有相同元素则自增i变量,跳出i的循环 b.如判断无时则将无相等值的元素推入到ret数组中
3.返回ret。
优点:便捷易懂,大多数程序员能想到。
缺点:很明显时间消耗太高,两层循环时间消耗太多,时间的消耗为O(n^2^),在进行大量数据处理时会消耗大量资源。而且该方法无法处理字符和数组,如下例:
var arr = [1,23,4,5,6,7,'1',22,3,1,2];
distinct(arr); //返回[23, 4, 5, 6, 7, "1", 22, 3, 1, 2]
所以我们可以开始考虑一些别的方法优化数组去重:
sort重排数组去除重复元素索引法(!每一个浏览器中的sort函数的排序方法并不一样,所以实现结果可能会有差异,经测试在chrome下测试别的数组实现会出现问题)
这种方法就是先讲原数组使用sort方法将数组重排,以得到将相同元素为相邻位的一个新数组。该方法如下:
function distinct(arr){
var self = arr;
list = self.concat().sort();
list.sort(function(a, b){
if(a === b){
var ind = self.indexOf(a);
self.splice(ind, 1);
}
});
return self;
}
var arra = [1,2,3,3,1,1,1,'1'];
var arr = distinct(arra); //返回的数组为[2,3,1,'1']
同样的,在使用这种方法的重排的时候,仍然会有一定的资源消耗,在sort()函数中回调函数是使用的冒泡排序,而冒泡排序的效率并不高。但是使用这种方法的效率仍然比上一种方法的效率高,因为在此例中只出现了一次循环遍历。
优点:程序简洁,效率较高。
缺点:1.仍然无法解决数字1和字符'1'的去除。2.依赖indexOf方法,我们知道在IE6~8中并未支持indexOf()方法。
所以我们还要做一些兼容性的处理。如下:
var indexOf = [].indexOf ?
function indexOf(arr, item){
return arr.indexOf(item);
}:
function indexOf(arr, item){
for(var i = 0; i < arr.length; i++){
if(arr[i] === item){
retrun i;
}
}
return -1;
}
function distinct(arr){
var self = arr;
list = self.concat().sort();
list.sort(function(a, b){
if(a === b){
var ind = self.indexOf(arr, a);
self.splice(ind, 1);
}
});
return self;
}
将数组元素值存为对象的属性
function distinct(arr) {
var ret = [],
json = {},
length = arr.length;
for(var i = 0; i < length; i++){
var val = arr[i];
if(!json[val]){
json[val] = 1;
ret.push(val);
}
}
return ret;
}
var arra = [1,2,3,5,7,1,2,'1'];
以上方法更加的简洁,而且也能在原来的基础上区分字符‘1’和数字1的区别。
在此例中思路如下:
1.循环遍历每一个元素
2.检测在json对象中是否含遍历到的元素的值
a: 如果是则跳过
b: 如果否存入json对象中该属性名的值设为1
3.将存入对象了元素的值推入到新数组中,返回新数组。
总结,其实数组去重无非就是判断一个元素在数组中是否有重复的值。优化也是一直改变判定元素是否重复的一些技巧,如例1中是遍历数组,例2是重排数组获得索引,例3则别出心裁将元素的值作为对象的属性。
参考自:
从 JavaScript 数组去重谈性能优化
也谈javascript数组去重
js数组去重
谢谢@飞的更高 指出的问题
同步于个人博客:http://penouc.com
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。