在之前有次面試的時候,當場敲代碼就出了數組去重。當時正好看到 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/ */