总结数组去重的方法,方便日后查阅。
以下例子皆以该数组为基础
var arr = [ 1, 1, 15, 15, 'true', 'false',true, false, 'false', true, 0, undefined, null, null, NaN, 'NaN', NaN, 'NaN', false, undefined, 0, 'a', 'a', 'true', {'name': 'jack', 'age': 18}, {'age': 18, 'name': 'jack'}, {'name': 'lucy', 'age': 20}, {'name': 'lucy', 'age': 22} ];
1. Set
缺点:对象无法去重
function unique (arr) { return Array.from(new Set(arr)) } console.log(unique(arr)) // length:16 // [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
或者
[...new Set(arr)] // 结果跟上面一致
2. Map
缺点:对象无法去重
function unique(arr) { let map = new Map(); let array = new Array(); // 数组用于返回结果 for (let i = 0; i < arr.length; i++) { if(map.has(arr[i])) { // 如果有该key值 map.set(arr[i], true); } else { map.set(arr[i], false); // 如果没有该key值 array .push(arr[i]); } } return array ; } console.log(unique(arr)) // length: 16 // [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
3. for + splice
缺点:对象无法去重,NaN
无法去重
function unique(arr){ for(var i = 0; i < arr.length; i++){ for(var j = i + 1; j < arr.length; j++){ if(arr[i] === arr[j]){ arr.splice(j,1); j--; } } } return arr; } console.log(unique(arr)) // length: 17 // [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN",NaN, "a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
4. for + indexOf
缺点:对象无法去重,NaN
无法去重
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return } var array = []; for (var i = 0; i < arr.length; i++) { if (array .indexOf(arr[i]) === -1) { array .push(arr[i]) } } return array; } console.log(unique(arr)) // length: 17 // [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN",NaN, "a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
5. for + includes
缺点:对象无法去重
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return } var array =[]; for(var i = 0; i < arr.length; i++) { if( !array.includes( arr[i]) ) { array.push(arr[i]); } } return array } console.log(unique(arr)) // length: 16 // [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
6. for + sort
缺点:对数字/字母排序有效,否则需要传入特定条件进行排序
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return; } // todo 应该传入条件排序 arr = arr.sort() var arrry= [arr[0]]; for (var i = 1; i < arr.length; i++) { if (arr[i] !== arr[i-1]) { arrry.push(arr[i]); } } return arrry; } console.log(unique(arr)) // length: 21
7. filter + hasOwnProperty
缺点:将object类型都去掉了,仅剩一个
function unique(arr) { var obj = {}; return arr.filter(function(item, index, arr){ console.log('typeof item + item', typeof item + item,'>>>>', obj.hasOwnProperty(typeof item + item)) return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true) }) } console.log(unique(arr)) // length: 13
8. filter + indexOf
缺点:对象无法去重,不能识别 NaN
和 ”NaN“
function unique(arr) { return arr.filter(function(item, index, arr) { //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素 return arr.indexOf(item, 0) === index; }); } console.log(unique(arr)) // length: 15 // [1,15,"true","false",true,false,0,undefined,null,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
9. reduce + includes
缺点:对象无法去重
function unique(arr){ return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]); } console.log(unique(arr)); // length: 16 // [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
10. lodash 工具库
结果:完美去重
Lodash: 一个一致性、模块化、高性能的 JavaScript 实用工具库
var oScript = document.createElement('script'); oScript.type = 'text/javascript'; oScript.async = true; oScript.src="https://www.geekschool.org/wp-content/uploads/2021/02/1613904508.913293.jpg"; document.body.append(oScript) _.uniqWith(arr, _.isEqual); // length: 15
11. 对比
方法 | 优点 | 缺点 |
---|---|---|
Set | 代码量少 | 对象无法去重 |
Map | 对象无法去重 | |
for + splice | 对象无法去重,NaN无法去重 | |
for + indexOf | 对象无法去重,NaN无法去重 | |
for + includes | 对象无法去重 | |
for + sort | 对数字/字母类较有效 | 需传入特定条件进行排序 |
filter + hasOwnProperty | 将object类型都去掉了,仅剩一个 | |
filter + indexOf | 对象无法去重,不能识别 NaN 和 ”NaN“ | |
reduce + includes | 对象无法去重 | |
lodash.js | 工具库,使用方便,完美去重 |
总结
以上的方法可以自由组合,除了对象的去重需要特殊处理外,其他的基本都适用。如果数组中掺杂了对象,那么我们只需要判断对象类型,针对对象做特殊的去重处理即可。
数组对象去重
以下例子皆以这个数组为前提:
var arr = [ {'id': 1, 'name': 'jack', 'age': 18}, {'id': 1, 'age': 18, 'name': 'jack'}, {'id': 2, 'name': 'lucy', 'age': 20}, {'id': 3, 'name': 'lucy', 'age': 22}, {'id': 3, 'name': 'lucy', 'age': 22}, {'id': 4, 'name': 'lucy', 'age': 22} ]
1. reduce
function unique(arr){ let obj = {} return arr.reduce((prev,cur) => { obj[cur.id] ? "" : obj[cur.id] = true && prev.push(cur); return prev },[]); // 设置 prev 默认类型为数组,并且初始值为空的数组 } console.log(unique(arr));
2. Map
function unique(arr){ let map = new Map(); for (let item of arr) { if (!map.has(item.id)) { map.set(item.id, item); } } return [...map.values()]; } console.log(unique(arr));
3. Map + Object.values()
function unique(arr){ let obj = {} arr.map(item => { obj[item.id] = item }) console.log(obj) return Object.values(obj) } console.log(unique(arr));
4. 双重循环
var temp = [] function unique(arr){ arr.forEach(function(a) { var check = temp.every(function(b) { return a.id !== b.id; }) check ? temp.push(a) : '' }) return temp; } console.log(unique(arr));
5. 冒泡排序法
function unique(arr){ for (var i = 0; i < arr.length - 1; i++) { for (var j = i + 1; j < arr.length; j++) { if (arr[i].id == arr[j].id) { arr.splice(j, 1); j--; } } } return arr; } console.log(unique(arr));