数组去重-

 

数组去重:将数组中重复的元素找出来并删减为一个。目的很简单,方法倒有很多,以至于我费尽心思去考虑各种方法的好处坏处并进行对比,最终得出在各种场合适用的不同方法。希望有不同意见的尽管指出来。

【方法1】:

 

/*
* function unique1(array)
* 原理:新定义一个数组,结合一个对象辅助
* 时间复杂度:O(n)
* 适用范围:全数字、全字符串
* 方法缺点:混淆数字与数字字符串,对于对象无效
*/ 
function unique1(array) {
if (!array) return array;
var obj = {}, a = [];
for (var i = 0, iLen = array.length; i < iLen; i++) {
if (!obj[array[i]]) {
a.push(array[i]);
obj[array[i]] = true;
}
}
return a;
}

简单易懂的方法,但是对于只含数字的字符串(如 '12')无法和数字区分开来,对于对象也无法区分,可以在底部的测试例子中看到。

【方法2】:

 

 

 

/*
* function unique2(arr)
* 原理:新定义一个数组,结合一个对象辅助
* 时间复杂度:O(n)
* 适用范围:全数字、全字符串、数字与字符串混合
* 方法缺点:对于对象,所有对象最后只剩一个(不管键值对是否相同)
*/
function unique2(array) {
        if (!array) return array;
        var obj = {}, a = [];
        for (var i = 0, iLen = array.length; i < iLen; i++) {
            if ((typeof obj[array[i]]) != (typeof array[i]) || obj[array[i]] != array[i]) {
                a.push(array[i]);
                obj[array[i]] = array[i];
            }
        }o=obj;
        return a;
    }

 

这种方法在方法1的基础上,能够分辨出数字字符串和数字,但对于对象仍无能为力。

【方法3】:

 

 

 

 

/*
* function uniqExceptObj(array)
* 原理:查找相同值,对数组进行splice修改
* 时间复杂度:O(n2)
* 适用范围:全数字、全字符串、数字与字符串混合、含有对象(不同对象的键值对均不同)
* 方法缺点:无法区分具有相同键值对的不同对象
* 注意!array.length不要事先获取,如 iLen=array.length; 因为循环过程中array.length会变化
*/

function uniqExceptObj(array){
var temp = array.slice(0); //设置一个辅助数组,避免直接修改原array数组
for(var i = 0; i < temp.length; i++){
for(var j = i + 1; j < temp.length; j++){
if(temp[i] === temp[j]){
temp.splice( j, 1 );
j--;
}
}
}
return temp;
}

 

现在,对于对象也可以区分了。但是仍然无法区分具有相同键值对的不同对象,那么这也不是真正意义上的去重。并且,时间复杂度已经达到了O(n2)了。

【方法4】:

 

/*
* function uniqueAll(array)
* 原理:用equal函数查找相同值,对数组进行splice修改
* 时间复杂度:O(n3)
* 适用范围:全部
* 方法缺点:复杂度太大,时间消耗太大
* 说明:内置辅助函数 isEqual
* 注意!array.length不要事先获取,如 iLen=array.length;
*/

function uniqueAll(array){
/* function isEqual(obj1,obj2)
* 功能:比较任何类型的两个元素
* 结果:只有两个元素类型相同且值相同时才返回真
*/
function isEqual(obj1,obj2){
if (obj1 === obj2) { return true; }
if (!(obj2 instanceof Object) || (obj2 === null)) { return false; } // null is not instanceof Object.
var p = 0; // count propoty of obj1
for (var k in obj1){
p++;
var o1 = obj1[k];
var o2 = obj2[k];
if ((o1 != null) && !(isEqual(o1,o2))){ return false; } // compare inner object.
}
for (var k in obj2){ // compare object property counter.
p--;
}
return p == 0;
}
var temp = array.slice(0); //设置一个辅助数组,避免直接修改原array数组
for(var i = 0; i < temp.length; i++){
for(var j = i + 1; j < temp.length; j++){
if( isEqual( temp[i],temp[j] )){
temp.splice(j,1);
j--;
}
}
}
return temp;
}

仍是用方法3的思路,把各个数组元素进行对比,只是在对比时用了一个内置函数isEqual,用来有效地比较各种类型,包括对象。这种方法可以有效地对任何类型数据进行处理,但缺点明显,时间复杂度O(n3)。所以,在不需要对对象处理的时候,还是避免使用的好。

 

 

【终于到结论了】:
从以上的各种对比来看,我们可以得出一个前人早已得出的结论:“人无完人,金无足赤”。各个方法有各自不同的优点和缺点。
当只需要处理字符串或只需要处理数字时,我们可以采用方法1;
当需要处理字符串和数字混合的数组而无需处理对象时,我们采用方法2;
当只需处理去掉同个对象而不需处理多个键值对相同的对象时,可以采用方法3;
当要求对不同对象但键值对相同的对象进行去重时,我们可以采用方法4。

原址:http://chanthuang.blog.163.com/blog/static/16812743820133725815167/

posted @ 2014-09-22 20:43  林璐  阅读(157)  评论(0编辑  收藏  举报