十二月 27th, 2009

删除数组的重复项

前端开发, by army8735.

怿飞在同名文章《删除数组中重复项(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等,则会更加复杂。

Back Top

回复自“删除数组的重复项”

  1. 介绍给你一种更好的实现方式,以前就写过了。利用数组的lastIndexOf和splice方法。
    http://www.welefen.com/javascript-array-unique/

  2. 这个啊,我在土豆网写过一个实现,支持混合类型:

    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"]);

  3. @Dexter.Yy: 好东西。你的站点咋打不开呢?

  4. @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个方法:一个适用于小数组多循环,一个适用于大数组少循环。

  5. @Dexter.Yy: 突然觉得这个方法应该多加一个参数:是否支持强类型。因为毕竟实际运用中大多数数组还不会是那种复合类型的,加一个参数可以减少消耗。
    或者干脆写成2个方法:支持类型判别和不支持的。

  6. 这种方式对于大数组的情况确实很快,但还是有个遗漏的情况。如:new String(‘a’)和new String(‘a’)。
    它们的类型相同,toString结果也相同,但两个对象却不相等。
    通过上面的方式过滤后只剩下一个了。

  7. @welefen: 这个就是我说的不支持复合类型了……

  8. 提供的方法不错,和Dexter.Y有些神似,呵呵
    PS:我的名字写错了,呵呵,是怿飞

  9. @怿飞: 我一直都读ze……汗……改过来。

  1. 没有任何引用。

发表回复

Back Top