Javascript数组去重 方法总结

如果什么都不去参考,只给我一个编辑器的话,让我实现去除javascript数组中重复元素的方法的话,我会这么写:

var test_array = [1, 1, 2, 2, 3, 'a', 'a', '2', '3'];

/**
 * javascript数组去重方法
 * @param  {Array} arg [所要去重的数组]
 * @return {Array}     [去重后新的数组]
 */
function no_repeat_1(arg){
	var _arg = [];
	var _len = arg.length;
	for(var i = 0; i < _len; i++){
		if(in_array(arg[i], _arg, true)){
			continue;
		}
		_arg.push(arg[i]);
	}
	return _arg;
}

/**
 * 检查数组中是否存在某个值
 * 
 * @param  {Mixed} needle [给定的某个元素]
 * @param  {Array} haystack [所要查找的数组]
 * @param  {Boolean} strict [如果为true 则会检查 needle 的类型是否和 haystack 中的相同]
 * @return {Boolean} [在 haystack 中搜索 needle ,如果找到则返回 TRUE,否则返回 FALSE]
 */
function in_array(needle, haystack, strict){
	if(typeof needle == undefined || typeof haystack == undefined){
		return false;
	}
	var len = haystack.length;
	for(var i = 0; i < len; i++){
		if(strict){
			if(needle === haystack[i]){
				return true;
			}
		} else {
			if(needle == haystack[i]){
				return true;
			}
		}
	}
	return false;
}

console.log(no_repeat_1(test_array));

我思路主要是这样的:

首先遍历这个要去重的数组,然后用in_array()方法判断,当前元素是否已经存在于当前的临时数组_arg中,如果存在,则continue跳过,否则,push当前的这个元素到_arg这个数组中,遍历完成之后,返回这个临时数组_arg,即为去重后的数组。

注:我写的这个in_array() 方法第三个参数如果为true ,则会检查元素的类型是否相同。

恩,就是这样的,这是我首先想到的一个方法。

不过,我想应该还要更好的方法,好吧,接下来,我就分析一下从网络中找的一些数组去重的方法。

下面是YUI中的源码:

var test_array = [1, 1, 2, 2, 3, 'a', 'a', '2', '3'];

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 yui_uniq= function(a) {
	return keys(toObject(a));
};

console.log(yui_uniq(test_array));

该方法的思路:《巧妙去除数组中的重复项》

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

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

该方法的特点:

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

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

来看看 怪飞的写法:

var test_array = [1, 1, 2, 2, 3, 'a', 'a', '2', '3'];

var planabc_uniq = function (arr) {
	var a = [],
		o = {},
		i,
		v,
		cv, // corrected value
		len = arr.length;

	if (len < 2) {
		return arr;
	}

	for (i = 0; i < len; i++) {
		v = arr[i];

		/* closurecache 提供的函数中使用的是  cv = v + 0;,
		 * 这样就无法辨别类似[1, 10, "1", "10"]的数组,
		 * 因为运算后 => 1, 10, 10, 100,很明显,出现了重复的标示符。
		 * 加前面就难道没问题吗?
		 * 有的:数组中不能出现类似01 、001,以 0 开头的数字,
		 * 但适用性比原先更广。
		 */
		cv = 0 + v;

		if (!o[cv]) {
			a.push(v);
			o[cv] = true;
		}
	}
	return a;
}

console.log(planabc_uniq(test_array));

该方法的特点是:只用一次循环便完成了删除数组中重复项,性能远高于YUI的写法。

恩,下面稍微的改进了一下第一种方法:

var test_array = [1, 1, 2, 2, 3, 'a', 'a', '2', '3'];

if(!Array.prototype.indexOf) {
	Array.prototype.indexOf = function (obj, fromIndex) {
		if (fromIndex == null) {
			fromIndex = 0;
		} else if (fromIndex < 0) {
			fromIndex = Math.max(0, this.length + fromIndex);
		}

		for (var i = fromIndex; i < this.length; i++) {
			if (this[i] === obj)
				return i;
		}
		return -1;
	};
}

function no_repeat_2(arg){
	var _arg = [];
	for(var i = 0; i < arg.length; i++){
		if(_arg.indexOf(arg[i]) != -1){
			continue;
		}
		_arg.push(arg[i]);
	}
	return _arg;
}

console.log(no_repeat_2(test_array));

简单分析上面的几种方法,我觉得我写的第一种方法,性能上没啥优势,只能说思路清晰,很易懂,具体性能那个好,明天我会写个测试页面专门测试一下他们的执行效率。

这篇文章目前有1条评论

Leave a Reply

(必填项)

(必填项)

(可选)