数组去重
```js // 数组去重方法总结 // v1. 双层循环去重 function unique(arr) { let res = []; // 外层循环遍历原始数组 for (var i = 0, arrLen = arr.length; i < arrLen; i++) { // 内层循环遍历res数组 for (var j = 0, resLen = res.length; j < resLen; j++) { if (arr[i] === res[j]) { break; } } // 关键点:遍历完毕之后,如果arr[i]是唯一的,那么必定满足j===resLen if (j === resLen) { res.push(arr[i]); } } return res; } // 优点: 兼容性好
// v2. indexOf去重 function unique(arr) { var res = []; for (var i = 0, len = arr.length; i < len; i++) { var cur = arr[i]; if (res.indexOf(cur) === -1) { res.push(cur); } } return res; } // 优点:使用indexOf可以简化内层循环
// v3. 先排序,然后去重 function unique(arr){ var res = []; // 排序之后的数组 var sortedArr = arr.concat().sort(); // seen表示的是当前的比较项 var seen; // v1 /for (var i = 0, len = sortedArr.length; i < len; i++) { // 从第一个元素开始,比较相邻的元素是否相同 if (!i || seen !== sortedArr[i]) { res.push(sortedArr[i]); } seen = sortedArr[i]; }/
// v2
for (var i = 0, len = sortedArr.length; i < len; i++) {
// 最后一个和undefined比较
if (sortedArr[i] !== sortedArr[i+1]) {
res.push(sortedArr[i]);
}
}
return res;
}
// v4. 封装一个unique的API【重点掌握】 function unique(arr, isSorted){ var res = []; var seen = [];
for (var i = 0, len = arr.length; i < len; i++) {
var value = arr[i];
// 根据是否排序选择去重方式
if (isSorted) {
// 这个排序方法要学会
if (!i || seen !== value) {
res.push(value);
}
seen = value;
}
else if (res.indexOf(value) === -1) {
res.push(value);
}
}
return res;
}
// TODO: 如何把字母的大小写视为一致,比如'a'和'A',保留一个就可以了? // v5: 去重API增强 /**
- 去重API增强
- @param arr 表示要去重的数组,必填
- @param isSorted 表示函数传入的数组是否已排过序,如果为 true,将会采用更快的方法进行去重
- @param iteratee 传入一个函数,可以对每个元素进行重新的计算,然后根据处理的结果进行去重
@return {Array} */ function unique(arr, isSorted, iteratee){ var res = []; var seen = [];
for (var i = 0, len = arr.length; i < len; i++) {
var value = arr[i]; // 处理iteratee参数 var computed = iteratee ? iteratee(value, i, arr) : value; if (isSorted) { if (!i || seen !== value) { res.push(value); } // 更新为最新的computed数据(是经过iteratee这个函数处理之后的结果) seen = computed; } else if (iteratee) { // 处理iteratee的核心逻辑 if (seen.indexOf(computed) === -1) { // seen里面放的是转换处理之后的数值 seen.push(computed); // 结果里面放入的始终是数组的原始值,而不是经过转换之后的数值 res.push(value); } } else if (res.indexOf(value) === -1) { // 常规去重方法 res.push(value); }
} return res; }
// TODO: 使用filter函数简化外层循环? // v6. filter简化去重逻辑 // 使用indexOf简化 function unique(arr){ var res = arr.filter(function (item, index, self) { // indexOf实际上找到的是第一次出现的位置 return self.indexOf(item) === index; }); return res; }
// 使用排序去重的方法 function unique(arr) { return arr.concat().sort().filter(function (item, index, self) { // 后面的一项和前面的项进行比较 return !index || item !== self[index - 1]; }); }
// v7. 使用Object键值对去重(推荐使用,可以去重所有的数据类型) function unique(arr) { var obj = {}; var res = arr.filter(function (item) { // 问题1: 无法区分1和'1' // return obj.hasOwnProperty(item) ? false : (obj[item] = true);
// 问题2: 无法区分{value: 1}和{value: 2}
// { number1: true,
// stringa: true,
// stringA: true,
// number2: true,
// stringb: true,
// stringc: true,
// number3: true }
// return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true);
// 最终解决方案:使用JSON.stringfy, 先把对象序列化处理
let temp = typeof item + JSON.stringify(item);
return obj.hasOwnProperty(temp) ? false : (obj[temp] = true);
});
console.log('obj now:', obj)
return res;
}
// v8: ES6去重大法 function unique(arr){ return Array.from(new Set(arr)); } // 代码简化1 function unique(arr){ return [...new Set(arr)]; } // 代码简化2 var unique = (a) => [...new Set(a)];
// 使用Map去重 function unique(arr){ const seen = new Map(); return arr.filter(a => !seen.has(a) && seen.set(a, 1)); }
console.log(unique([1, 2, 3, 2, '1'])) console.log(unique([1, '1', 2, 3], true)) console.log(unique([1, 1, 'a', 'A', 2, 'b', 'c', 3, '1', {value : 1}, {value: 2}, {value: 1}], false, function (item, index, arr) { return typeof item === 'string' ? item.toLowerCase() : item; }))
var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN]; console.log(unique(array));
```