在之前有次面试的时候,当场敲代码就出了数组去重。当时正好看到 Set ,直接转 Set 再转 Array出告终果。而后面试官又问了问 Set 背后是作了什么工做,能不能手动循环作一下。惭愧的是经提醒,才写出了拿一个辅助Array去记录不重复的数据。方法单一,也没有涉及特殊的基本类型值和复杂的引用者。 这里作一个从新的梳理,数组去重分两步:git
这第一式:双层循环+严格等价github
//外招:双层循环 + 内招:严格等价
function deduplicate(arr){
//记录惟一数据
var help_arr = [];
for(var i=0;i<arr.length;i++){
for(var j=0;j<help_arr.length;j++){
if(arr[i]===help_arr[j]){
break;
}
}
//能走到这里说明没有知足严格等价
if(j===help_arr.length){
help_arr.push(arr[i]);
}
}
return help_arr;
}
复制代码
这第二式:单层循环+arr#indexOf面试
function deduplicate(arr){
//记录惟一数据
var help_arr = [];
for(var i=0;i<arr.length;i++){
//若是没有找到
if(!~help_arr.indexOf(arr[i])){
help_arr.push(arr[i]);
}
}
return help_arr;
}
复制代码
这第x式:arr#filter+arr#indexOf数组
function deduplicate(arr){
return arr.filter((element,index,array)=>array.indexOf(element)===index);
}
复制代码
这一式使用了 arr#filter 大大简化了代码。安全
其实前面这三式内招都是同样的,arr#indexOf 底层仍是用了严格等价。 可是对于有些值是没法作到去重的:bash
function deduplicate(arr){
let countNaN = 0;
return arr.filter((element,index,array)=>{
if(countNaN===0&&Number.isNaN(element)){
countNaN++;
return true;
}else{
return array.indexOf(element)===index;
}
});
}
复制代码
使用 Number.isNaN或者Object.is对值NaN作特殊处理。数据结构
function deduplicate(arr){
return [...new Set(arr)];
}
复制代码
嗯...开挂同样,这也是我当时面试的时候写出来最快的...使用数据结构Set达到的效果也是能处理NaN。ui
JSON.stringify + JSON.parse 能帮助部分对象去重,说是部分是由于有JSON字符串非安全值:undefined、function、(ES6+)symbol、和带有循环引用的 object,若是对象包含这些值特殊状况就会增多。spa
function deduplicate(arr){
//引用值作JSON字符串化
const objTransArr = arr.map(e=>{
if(typeof e === "object" && e){
return JSON.stringify(e);
}else{
return e;
}
})
let countNaN = 0;
return arr.filter((element,index,array)=>{
if(countNaN===0&&Number.isNaN(element)){
countNaN++;
return true;
}else if(typeof element === "object" && element){
return objTransArr.indexOf(JSON.stringify(element))===index;
}else{
return array.indexOf(element)===index;
}
});
}
复制代码
这里由于只想对数组内的引用数据作JSON字符串化,因此引入了辅助数组 objTransAff,它是能解决 NaN 和 object/array/regx 的去重,只要引用数据类型内不涉及JSON非法值。code
function deduplicate(arr){
let obj = {};
return arr.filter((v,i,array)=>{
const k = typeof v + JSON.stringify(v);
return obj.hasOwnProperty(k)?false:(obj[k]=true);
})
}
复制代码
这一招其实挺妙的,经过 typeof v + JSON.stringify(v) 转化为对象的key,这里也解决了NaN和引用数据类型的问题。
到最后其实也没有拿出一个沉重的解决全部去重的方案,可是走到这一步我的认为已是足够了,由于实际状况下的数组去重并不须要走这么远,如今列出各招数的缺陷,具体状况具体应用就行。
严格等价/arr#indexOf | 缺陷:NaN、引用数据 |
---|---|
严格等价+Number.isNaN(..)/Object.is(..,..) | 缺陷:引用数据 |
Set | 缺陷:引用数据 |
Number.isNaN(..)/Object.is(..,..)+JSON.stringify+JSON.parse | 缺陷:含JSON非法值的引用数据 |
Object键值对+JSON.stringify | 缺陷:含JSON非法值的引用数据 |
按能力从小到大的推荐方法是:
参考连接: JavaScript专题之数组去重:这篇写得超级好!
/*封面图是盗来的,原做者在这:https://kaminario.com/company/blog/data-dedupe-all-flash-arrays/ */