数组去重
数组去重是一个很常见的需求,而实现的方式也多种多样,接下来我们来看看有哪些实现方式。
一、普通方法
创建一个空数组 `arr`,遍历原始数组(this)的每一项,如果当前项不存在 `arr` 中,则 `push` 进 `arr`
缺点:这里其实是两层遍历。第一层是外层的 `for` 循环,第二层是内部的 `indexOf` 判断
Array.prototype.unique = function() {
var arr = [];
var len = this.length;
for(var i=0; i<len; i++) {
if(arr.indexOf(this[i]) === -1) arr.push(this[i]);
}
return arr;
}
二、较快的方式
使用对象(hash)的方式来记录是否已经存在
Array.prototype.unique = function() {
var json = {};
var arr = [];
var len = this.length;
for(var i=0; i<len; i++) {
if(typeof json[this[i]] === "undefined") {
json[this[i]] = true;
arr.push(this[i]);
}
}
return arr;
}
但是有时我们会发现上述方法失灵了,例如数组:`[1, "1", 2, 2]`
我们希望去重之后得到的结果是:`[1, "1", 2]`,但是会发现结果变成了 `[1, 2]`
这其实是因为我们在使用 `hash` 的时候,就是把数组元素作为 `hash` 的 `key` 值了,那么在使用过程中就会把**数组元素变成字符串**。
- 解决方案:使用 `Object.prototype.toString.call`
可以具体判断出 `key` 的数据类型
json[this[i]] = {}; // json[1] = {}
// json[1]["[object Number]"] = 1
// json[1]["[object String]"] = 1
json[this[i]][Object.prototype.toString.call(this[i])] = 1;
`json` 中的每一项,也都是一个对象。内部对象的 `key` 值为当前循环项的类型,外部对象(`json`)的 `key` 值为当前循环项的**字符串内容**
例如:`[1, "1"]`,在 `json` 的存储中就会变为
json = {
1: {
"[object Number]": 1, // value赋值为1,就可以统计重复的数量了,具有更好的扩展性
"[object String]": 1
}
}
Array.prototype.unique = function() {
var json = {}, arr = [], len = this.length;
for(let i=0; i<len; i++) {
var type = Object.prototype.toString.call(this[i]); // 类型
if(typeof json[this[i]] === "undefined") { // 如果json[1]为undefined,则对其初始化
json[this[i]] = {}; // 初始化为空对象
json[this[i]][type] = 1; // json[1]["[object Number]"] = 1,记录为1
arr.push(this[i]); // 在新数组中添加当前项
} else if(json[this[i]][type] === "undefined") { // json层的对象已经初始化过了,但内部type为key的内容还没记录过
// 类似于:json[1]["[object Number]"]有值,但json[1]["[object String]"]未定义
json[this[i]][type] = 1;
arr.push(this[i]);
} else { // 剩下的就是定义过的,直接+1就行了
json[this[i]][type]++;
}
}
}
缺点:不能为对象去重。如果传入的数组为 `[{ a: 1 }, {}]`,则去重的结果就是 `[{ a: 1 }]`,因为对象转为字符串后都是 `[object Object]`
三、排序后对比
- 先对数组进行排序:可以让相同的数据挨在一起
- 定义一个新的空数组
- 遍历排序后的数组
- 如果当前项等于新数组的最后一项,则跳过
- 如果不等于,则将当前项插入新数组
Array.prototype.unique = function() {
this.sort(); // 先排序
var arr = [], len = this.length;
for(var i=0; i<len; i++) {
if(this[i] !== arr[arr.length - 1]) { // 如果当前项不等于arr的最后一项
arr.push(this[i])
}
}
return arr
}
四、利用ES6的Set
function unique(arr) {
return [...new Set(arr)];
}
不考虑兼容性的话,这种去重的方法代码量最少。
const arr = [1, "1", {}, {}];
console.log(unique(arr)); // [ 1, '1', {}, {} ]
通过上述代码的打印结果,可以看出 `new Set` 的方法可以区分出数据类型,但是无法去掉相同对象。(本质上是因为对象都是引用)
五、利用Map去重
function unique(arr) {
const map = new Map();
const array = [];
for (let i = 0; i < arr.length; i++) {
if (map.has(arr[i])) { // 如果已经存在了,则将其值设为 true(说明是重复元素)
map.set(arr[i], true);
} else { // 否则将其值设为false(目前没重复)
map.set(arr[i], false);
array.push(arr[i]);
}
}
return array;
}
数组去重的多种实现方法解析
本文详细介绍了数组去重的几种常见方法,包括普通遍历、使用对象哈希、排序对比、ES6 Set 和 Map 去重。针对不同情况,如基本类型与对象类型的数据,各种方法有不同的优缺点。例如,Set 方法简洁但无法处理对象去重,而Map方法可以区分数据类型但无法去除相同对象。最后,提供了每种方法的示例代码以供参考。
8万+

被折叠的 条评论
为什么被折叠?



