怿飞在同名文章《删除数组中重复项(uniq)》中分享了他的方法,时间复杂度和空间复杂度均为O(n),但还无法解决弱类型的问题。凑巧我也思考过类似的方法,在此基础上修改一下,可以KO弱类型问题。
<script src="mootools-1.2.4-core-nc.js"></script>
<script>
Array.implement({
distinct: function() {
if(this.length < 2) {
return this;
}
var hash = new Hash(), value;
outer:
for(var i = 0, len = this.length; i < len; i++) {
if(hash.has(this[i])) {
value = hash.get(this[i]);
for(var j = 0, len2 = value.length; j < len2; j++) {
if($type(this[i]) == value[j]) {
this.splice(i, 1);
i--;
len--;
continue outer;
}
}
value.push($type(this[i]));
}
else {
hash.set(this[i], [$type(this[i])]);
}
}
return this;
}
});
var arr = [0, 0, "0", '0', false, null, NaN, undefined, 1, "1", true];
alert(arr.distinct().join(", ")); //[0, "0", false, null, NaN, undefined, 1, "1", true]
</script>
基于mootools,我为Array类提供一个distinct方法,以供删除重复项。
基本思想是:遍历数组,建立一个hash用以统计出现过的每条项目。不过hash的key是数组每项的toString()值,value却是个类型数组。每遍历数组中的一个值时,首先检查hash中是否存在key,不存在设置value为一个新数组——并且里面有唯一的类型值(这个数组项的类型);如果hash中存在key,则遍历value,查找此数组项的类型是否在value中,在则说明重复,不在将类型push到value里面。
这样就解决了弱类型的问题,但如果数组中不仅仅有基本类型,还有数组、对象、arguments、hash等,则会更加复杂。

介绍给你一种更好的实现方式,以前就写过了。利用数组的lastIndexOf和splice方法。
http://www.welefen.com/javascript-array-unique/
这个啊,我在土豆网写过一个实现,支持混合类型:
TUI.unique = function( array ) {
var ret = [], record = {}, it, tmp;
var type = {
“number”: function(n){ return “_TUI_num” + n; },
“string”: function(n){ return n; },
“boolean”: function(n){ return “_TUI_boolean” + n; },
“object”: function(n){ return n === null ? “TUI_null” : $.data(n); },
“undefined”: function(n){ return “_TUI_undefined”; }
};
for ( var i = 0, length = array.length; i < length; i++ ) {
it = tmp = array[i];
tmp = type[typeof it](it);
if( !record[tmp] ) {
ret.push(it);
record[tmp] = true;
}
}
return ret;
};
测试:
var b=[1,3,5];
TUI.unique([1,3,4,5,null,false,$(".pack")[0],b,"ab","cc",[1,3],3,6,b,1,false,null,"null","","false","",$(".pack")[0],"cc"]);
@Dexter.Yy: 好东西。你的站点咋打不开呢?
@welefen: 我实际测试了一下,的确在循环10000次的时候你的方法很占优势,但是基于hash的方法在循环中主要消耗在创建hash对象上面,因此这个测试还很片面。
var arr = [];
for(var i = 0; i < 10000; i++) {
arr.push(i);
}
var d1 = new Date();
arr.distinct();
var d2 = new Date();
arrayUnique2(arr);
document.write((d2.getTime() – d1.getTime()) + “, ” + (new Date().getTime() – d2.getTime()));
更多的情况下是一个大数组进行单一化,这种情况下测试,你的方法太耗时了,因为时间复杂度是O(n2)。
我觉得可以考虑写成2个方法:一个适用于小数组多循环,一个适用于大数组少循环。
@Dexter.Yy: 突然觉得这个方法应该多加一个参数:是否支持强类型。因为毕竟实际运用中大多数数组还不会是那种复合类型的,加一个参数可以减少消耗。
或者干脆写成2个方法:支持类型判别和不支持的。
这种方式对于大数组的情况确实很快,但还是有个遗漏的情况。如:new String(‘a’)和new String(‘a’)。
它们的类型相同,toString结果也相同,但两个对象却不相等。
通过上面的方式过滤后只剩下一个了。
@welefen: 这个就是我说的不支持复合类型了……
提供的方法不错,和Dexter.Y有些神似,呵呵
PS:我的名字写错了,呵呵,是怿飞
@怿飞: 我一直都读ze……汗……改过来。