珠峰培训

数组去重

作者:tx

2016-07-03 22:38:52

171

双循环数组去重

var ary = [1,2,3,2,1,3];
拿这个简单的数组做例子,双循环的数组去重复的核心思想就是比较,那么如何做到比较不漏项才是关键
第一次拿出数组的第一项1,分别循环的和它后面的每一项做比较。如果有相同的就删掉。结果是把第五项1删掉
第二次拿出数组的第二项2,分别和它后面的所有项目做比较。如果有相同的就删掉。结果把2删掉
依次类推我们需要分别把数组的每一项和它后面的做比较,但是数组的最后一项后面已经没有项目了,所以就没
有必要比较了,所以最外层的循环是循环的一共拿多少次单个数组项目和后面做比较。是length-1项

第一次把第一项1那出来,然后和比它的索引大1的项开始比较到末尾,如果用i来循环每次拿出来的那一项,用j 循环来代表被比较的项(也就是拿出来的项后面的所有项目),那么j开始的索引一直都是比i大1

var ary = [1,2,3,2,1,3];
for (var i = 0; i < ary.length - 1; i++) { //这个循环代表的是每次都需要拿出来一个数组项目
for (var j = i + 1; j < ary.length; j++) { //这个循环代表每次拿出来项的后面所有项目
if (ary[i] === ary[j]) {
ary.splice(j, 1); //删除
//ary[j] = ary[ary.length-1];
//ary.length--;
j--; //由于删除产生的数组塌陷问题,故而需要原地重新循环一次。先j--后j++
}
}
}
console.log(ary);

对象法数组去重

var ary = [1,2,3,2,1];
var obj = {};
抛开数组在外我们先理解一个对象的知识点,拿我们上面的obj这个对象做例子,这是一
个空对象,没有任何一组属性。那么暂时可以说去读取这个对象的任意属性都是undefined
obj[ary[0]] = ary[0];
通过这一行代码,obj[‘属性名字’]这是给对象添加属性的另外一种方式,很显现我们是数
组的第一项作为属性名字给obj添加了一个属性值也是数组的第一项。添加之后的结果就是
obj = { 1:1 }
依次类推如果把数组的每一项都作为属性名字和属性值分别循环添加给obj那么obj一定到
最后会多三组属性,分别是obj = { 1:1,2:2,3:3 }
但是在添加数组的第四项2的时候我们发现这个属性名字以前在第二次添加过,那么这次也
就是把已经存在的属性修改,但是数组中的2出现的是第二次我们就可以认为这个2是是重
复项,那么就可以删掉了。
所以每次在做添加属性之前需要做判断,如果这个属性出现过,那么数组的项即作为属性
名字又作为属性值 obj[ary[i]] == ary[i] 这个等式一定是相等的

var ary = [1,2,3,4,2,1];
var obj = {};
for (var i=0; i<ary.length; i++){
var cur = newAry[i];
if(obj[cur] == cur){ //如果这个条件成立说明这个属性已经存在,就可以删除对应的数字里面的当前索引i项目

newAry.splice(i,1); //删除操作
i--; //这行代码很重要,如果删除操作数组的长度就会动态少了一项,那么当 前删除项目之后的项目就会一次向前提高了一个位置。那么下次循环从下一个位置开始就会把刚刚到删除项这个位置的项跳过去了。所以导致了漏项的问题。如果有删除项目,那么必须保证下次还要从这个原来位置开始。所以i--一次。这就是数组塌陷问题
continue; //如果有删除项说明这个删除项曾经作为属性名和属性值出现过,就没有必要继续做对象属性的修改操作了

//优化: 如果数组项目多,splice操作会导致后面所有的数组项目提前一个位置难免造成性能浪费,如果让最后一项的值赋值给当前项,那么中间的项就不用改变位置了

//ary[i] = ary[ary.length-1];
//ary.length--; 最后一项已经赋值当前删除位置就没有必要留下来了
//i--; 和以上的道理是相同的,只要有删除项目下次就应该从原地删除位置开始
}
}
obj = null; //对于一个已经没用的对象就可以赋值为null主动释放这个对象的堆内存
console.log(ary);

对象法数组去重是巧妙的利用的对象的属性名和属性值,但是需要注意一点,如果数组包含比如[]或者{}作为属性的时候就会有问题。所以最保险的方式还是双循环.需要注意的问题点,数组塌陷问题的处理