数组去重
数组去重是后续经常会用到以及面试中经常用到的知识点,最近在复习中整理了以下几种方法仅供大家参考。
原生方法
原理:
建立一个新数组,取出原数组的每一项和新数组的每一项作对比,将原数组中存在而新数组中不存在的元素添加到新数组中,最后返回新数组
具体实现(原型链上编程):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19Array.prototype.unique = function () {
var newArr = [this[0]]; //谁调用的unique方法,this指向谁(arr)
for (var i = 0; i < this.length; i++) {
var flag = true;
for (var j = 0; j < newArr.length; j++) {
if (this[i] === newArr[j]) {
flag = false;
}
}
if (flag) {
newArr.push(arr[i]);
}
}
return newArr;
}
var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var uniqueArr = arr.unique(); //方法调用
console.log(uniqueArr); //[1, 2, 13, 3, 4, 34]
需要注意的是:
1.第二个for循环遍历的次数为newArr.length,如果newArr为空,则不会进入for循环,将不会执行后面的语句。
2.第二个for循环里不能只是简单的根据条件判断arr[i] !== newArr[j]便试图直接调用newArr.push(arr[i])的方法来进行添加。
试想一下,当数组arr遍历到第3位(即1)时,此时newArr == [1, 2],newArr.length == 2;进入第二个for循环中,循环次数为2。
第一次循环时arr[i] === newArr[j] (即1 == 1),不会进入if循环;第二次arr[i] !== newArr[j] (即1 != 2),进入if语句,执行push语句,所以会再次向newArr中添加1,返回newArr = [1, 2, 1],以此类推。
即以下写法是错误的:1
2
3
4
5
6
7for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < newArr.lenght; j++) {
if (arr[i] !== newArr[j]) {
newArr.push(arr[i]);
}
}
}
利用对象的属性名无重复
原理:
对象的属性名是没有重复的,取出数组的每一位,看对象里面是否存在(即取出对象的属性名,看对应的属性值是否存在。如果不存在,则证明对象中没有这个属性,该元素在数组中是第一次出现,并将该元素添加到新数组中)。此时需要给不存在的属性赋值做标记
具体实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Array.prototype.unique = function () {
var obj = {};
var newArr = [];
for (var i = 0; i < this.length; i++) {
if(!obj[this[i]]) {
obj[this[i]] = 1;
newArr.push(this[i]);
}
}
return newArr;
}
var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var uniqueArr = arr.unique(); //方法调用
console.log(uniqueArr); //[1, 2, 13, 3, 4, 34]
调用splice()删除重复元素
原理:
取出数组中的每一个元素依次和后面的每一个元素对比,如果后面的元素有相同的则为重复元素,删除该元素
相关方法:
splice(start, length) 从第几位开始删除数组,删除几个长度,直接操作原数组,并返回原数组,数组中的每一项为删除的数据
slice(start, end) 截取数组的start位到end位(但不包括end位)的值,返回一个新数组。原数组不改变
具体实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14Array.prototype.unique = function () {
for (var i = 0; i < this.length; i++) { //谁调用的unique方法,this指向谁(arr)
for (var j = i + 1; j < this.length; j++) {
if (this[i] === this[j]) {
this.splice(j, 1);
}
}
}
return this;
}
var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var uniqueArr = arr.unique(); //方法调用
console.log(uniqueArr); //[1, 2, 13, 3, 4, 34]
indexOf()找出符合条件的第一个
原理:
根据indexOf()来判断该元素是否是第一次出现,即看当前元素的索引值是否是满足条件的第一个索引值。
相关方法:
Array.indexOf(item): 返回item元素在当前数组中第一次出现的索引值,不存在则返回-1。
具体实现:1
2
3
4
5
6
7
8
9
10
11
12Array.prototype.unique = function () {
for (var i = 0; i< this.length; i++) {
if(this.indexOf(this[i]) !== i) {
this.splice(i, 1);
}
}
return this;
}
var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var uniqueArr = arr.unique(); //方法调用
console.log(uniqueArr); //[1, 2, 13, 3, 4, 34]
filter()按一定规则遍历数组
原理:
用filter来遍历生成满足条件的新数组,判断的条件需要借助indexOf()来判断当前元素的索引是否等于当前的索引
相关方法:
filter(item, index, array) 有三个参数,第一个为数组的每一项(相当于arr[i]),第二个为当前元素的索引(i),第三个为原来的数组(即调用filter的那个数组)。
该方法会返回一个满足条件的新数组。
具体实现:1
2
3
4
5
6
7
8
9
10Array.prototype.unique = function () {
var newArr = this.filter(function (item, index, array) {
return array.indexOf(item) === index;
})
return newArr;
}
var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var uniqueArr = arr.unique(); //方法调用
console.log(uniqueArr); //[1, 2, 13, 3, 4, 34]
看到这里相信你应该已经明白,filter()方法就相当于for循环的封装,本质上还是取出数组中的当前项和当前索引,看该元素的索引值是不是第一次出现
sort()先排序,再去重
原理:
先将数组进行排序,相同的数据会排列在一起。
所以进行数组去重时只需要将当前数据与前一个数据作对比。如果当前数据不等于前一个数据,则说明该数据是第一次出现。
可以利用一个新数组,每次将数据添加到新数组时,通过判断当前的数据与新数组的最后一位是否相等。如果不相等,则将该数据push到新数组。
相关方法:
Array.sort() 默认将数组按照ASCII进行排序。
当里面传入一个回调函数时,即Array.sort(function (a, b) {return 1;})为升序排列;当return -1时为降序排列。
具体实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14Array.prototype.unique = function () {
this.sort();
var newArr = [];
for (var i = 0; i < this.length; i++) {
if (this[i] !== newArr[newArr.length - 1]) {
newArr.push(this[i]);
}
}
return newArr;
}
var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var uniqueArr = arr.unique(); //方法调用
console.log(uniqueArr); //[1, 13, 2, 3, 34, 4]
从结果可以看到,返回的数组根据ASCII升序排列。
Set()数据结构
原理:
调用ES6中的Set数据结构可以用于数组去重
具体实现:1
2
3var arr = [1, 1, 2, 1, 13, 2, 3, 4, 34];
var setArr = new Set(arr);
console.log(setArr);
结果: