巧妙去除数组中的重复项

时不时的看下YUI的源码, 总会有些收获.

最近, 我在看YAHOO.util.YUILoader类的源码, 其中有个排除数组重复项的方法, 让我觉得甚为巧妙, 这里分享下…

一. YUI中的源码

var toObject = function(a) {
      var o = {};
      for (var i=0, j=a.length; i<j; i=i+1) { // 这里我调整了下, YUI源码中是i<a.length
           o[a[i]] = true;
      }
      return o;
};
var keys = function(o) {
      var a=[], i;
      for (i in o) {
           if (o.hasOwnProperty(i)) { // 这里, YUI源码中是lang.hasOwnProperty(o, i)
               a.push(i);
           }
      }
      return a;
};
var uniq = function(a) {
      return keys(toObject(a));
};

注:为了书写方便, 我省略了各方法前的类名, 大伙可自行查阅YUI的源码, 2.7.0b与2.8.0r4均可(此部分的代码是一样的).

二. 该方法的思路

1. 先以目标数组的值为key生成一个对象. 这一步是最核心的: 因为在一个对象中, key是无法重复的, 这样就很巧妙的排除了重复值;

2. 遍历生成的对象, 将这些key取出来放到一个数组中, OK, 到此就大功告成了!(简单吧, 只需两步就行)

三. 该方法的特点

1. 对于该方法, 不论数组有多少项, 都只会遍历两次, 在性能上的优势较明显(想想自己以前的做法: 对数组项进行逐个对比, 其性能之差, 可想而知).

2. 经我的测试, 该方法只适用于数组项为字符串, 数字的一维数组(我觉得, 对多维数组进行排除重复项的操作, 实在是太杯具了!).

,

Comments

ada at 2009年12月22日 10:07 上午

var toObject = function(a) {
var o = {};
for (var i=0, j=a.length; i<j; i=i+1) { // 这里我调整了下, YUI源码中是i<a.length
if(Object.prototype.toString.apply(a[i]) === "[object Array]") {
o[a[i]] = toObject(a[i]) ;
} else {
o[a[i]] = true;
}
}
return o;
};
var keys = function(o) {
var a=[], i;
for (i in o) {
if (o.hasOwnProperty(i) && typeof o[i] === 'object') { // 这里, YUI源码中是lang.hasOwnProperty(o, i)
a.push(keys(o[i])) ;
} else {
a.push(i);
}
}
return a;
};
var uniq = function(a) {
return keys(toObject(a));
};

怿飞 at 2009年12月26日 5:03 下午

思路不错,其实可以只遍历一次。
var uniq = function (arr) {
var a = [],
o = {},
p,
v,
len = arr.length;
if (len < 2) {
return arr;
}
for (p in arr) {
v = arr[p];
if (1 !== o[v]) {
a.push(p);
o[v] = 1;
}
}
return a;
}

怿飞 at 2009年12月26日 5:08 下午

写错了一个地方:a.push(p);改为a.push(v);

怿飞 at 2009年12月26日 7:09 下午

又优化了下,将for (p in arr) 修改为:for(p=0;p<len;p++),详细见:http://www.planabc.net/2009/12/26/array_uniq/

Author comment by Tcer at 2009年12月26日 9:14 下午

哈哈, 改进的好, 性能上再次提升了!

删除数组中重复项(uniq) | 前端开发吧 at 2010年04月28日 9:36 上午

[...] 详细分析,见同事 长天 的分享 《巧妙去除数组中的重复项》。 [...]

Leave a comment!