在日常开发中,我们可能会遇到去重问题,这篇文章就是为了解决这个问题而写的。
为了方便使用,我们可以直接把封装的去重函数直接加入到数组的prototype中。
方法一:
Array.prototype.clearRepeat = function() {
var arr = []; //定义一个临时数组
for(var i = 0; i < this.length; i++) {
//通过遍历判断当前数组下标为i的元素是否保存到临时数组中
//如果保存,则跳过,否则保存到临时数组
if(arr.indexOf(this[i]) == -1) {
arr.push(this[i]);
}
}
return arr;
};
var test = [1, 6, 8, 8, 9, 9, 9, "a", "a"];
test.clearRepeat(); //结果为[1, 6, 8, 9, "a"]
方法二:
Array.prototype.clearRepeat = function() {
var arr = [this[0]]; //直接定义结果数组
for(var i = 1; i < this.length; i++) { //从第二项开始遍历当前数组
//对元素进行判断:
//如果当前数组元素在此数组中第一次出现的位置不是i
//则第i项是重复的,否则直接存入结果数组
if(this.indexOf(this[i]) == i) {
arr.push(this[i]);
}
}
return arr;
};
var test = [1, 6, 8, 8, 9, 9, 9, "a", "a"];
test.clearRepeat(); //结果为[1, 6, 8, 9, "a"]
上面两种方法不推荐使用,因为indexOf()这个函数在执行的时候每次都会遍历一次数组,对性能影响比较大。比较适合小数据量的数组。
方法三:
Array.prototype.clearRepeat = function() {
var h = {}; //定义一个hash表
var arr = []; //定义一个临时数组
for(var i = 0; i < this.length; i++) {
//对元素进行判断是否存在表中,如存在则跳过,否则存入临时数组
if(!h[this[i]]) {
h[this[i]] = true; //存入hash表
arr.push(this[i]);
}
}
return arr;
};
var test = [1, 6, 8, 8, 9, 9, 9, "a", "a"];
test.clearRepeat(); //结果为[1, 6, 8, 9, "a"]
上面这种方法使用的是hash表,把已经出现过的元素通过下标形式写入一个Object中,下标的引用要比数组的indexOf()方法搜索节省时间。
顺便补充下hash表的知识:
哈希表也叫散列表,是根据关键码值(key, value)而进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,以加快查找速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
通过测试发现上面这种方法存在一种缺陷,那就是当数组中同时出现类似于1和“1”这样的元素时,会把“1”这样的元素被去重。
var test = [1, 6, 8, 8, 9, 9, 9, "a", "a", "1"];
test.clearRepeat(); //结果为[1, 6, 8, 9, "a"],正确的应该为[1, 6, 8, 9, "a","1"]
查阅资料发现原因是因为:
作为下标在转换后会变成字符串,那么对于1和“1”这样不同类型的值会对应到同一个下标而被去重。
修改后的代码:
Array.prototype.clearRepeat = function() {
var h = {}; //定义一个hash表
var arr = []; //定义一个临时数组
for(var i = 0; i < this.length; i++) {
//对元素进行判断是否存在表中,如存在则跳过,否则存入临时数组
var type = typeof this[i];
if(!h[this[i] + type]) {
h[this[i] + type] = true;
arr.push(this[i]);
}
}
return arr;
};
var test = [1, 6, 8, 8, 9, 9, 9, "a", "a", "1"];
test.clearRepeat(); //结果为[1, 6, 8, 9, "a", "1"]
方法四:
Array.prototype.clearRepeat = function() {
this.sort(); //数组排序
var arr = [this[0]]; //定义结果数组
for(var i = 1; i < this.length; i++) { //从第二项开始遍历当前数组
//判断两个相邻元素是否相等,如果相等说明数据重复,否则将元素写入结果数组
if(this[i] !== arr[arr.length - 1]) {
arr.push(this[i]);
}
}
return arr;
};
var test = [1, 6, 8, 8, 9, 9, 9, "a", "a"];
test.clearRepeat(); //结果为[1, 6, 8, 9, "a"]
上面这种方法先将数组排序,然后比较相邻两个元素是否相等,若相等说明重复。数组排序采用的原生sort()。
上面四种方法的优劣和性能读者可以自行去测试。
如果你在本文中发现错误或者有异议的地方,可以在评论区留言,谢谢!