陣列去重算是個老生常談的問題了,不管是面試還是工作都會有所涉及,去重的方法比較多,不好說誰一定好誰一定差,可根據實際需求進行選擇。本文列舉一些常見的去重方法,並附上方法優劣與適用場合,如有紕漏請指正。
1. 二重循環對比法:
const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];function uniqueByCirculation(arr) { const newArr = []; let isRepet = false; for(let i=0;i < arr.length; i++) { for(let j=0;j < newArr.length; j++) { if(arr[i] === newArr[j]) { isRepet = true; } }; if(!isRepet) { newArr.push(arr[i]); }; }; return newArr; }const uniquedArr = uniqueByCirculation(array); console.log(uniquedArr);
結果:,從結果可以看出Array、Object、RegExp進行了保留, NaN沒有去重,原因就牽涉到「===」的比較機制了,詳情可閱:
此方法時間複雜度O(NlogN),空間複雜度O(N),適用場合:資料型別簡單,資料量少。
2. indexOf法:
const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];function uniqueByIndexOf(arr) { return arr.filter((e, i) => arr.indexOf(e) === i); }const uniquedArr = uniqueByIndexOf(array);console.log(uniquedArr);
結果:
程式碼簡單粗暴,從結果來看,NaN沒了,Array、Object、RegExp進行了保留,這是因為Array.indexOf(NaN)總是會回傳-1,其他複雜類型回傳的值總是等於自己index,因此得到這樣的結果。此方法時間空間複雜度和二重循環一致,適用場合相仿,當然二者相比還是首推這個,畢竟程式碼短啊。
3. Object[key]法: (個人深度加強版)
const array = [1, '1', NaN, 1, '1',NaN, -0, +0, 0, null, /a/, null, /a/, [], {}, [], {}, [1,2,[2,3]], [1,2,[2,3]], [1,2,[3,2]], undefined, {a:1,b:[1,2]}, undefined, {b:[2,1],a:1}, [{a:1},2], [2,{a:1}], {a:{b:1,d:{c:2,a:3},c:1},c:1,d:{f:1,b:2}}, {a:{b:1,d:{c:2,a:3},c:1},c:1,d:{f:1,b:2}}];function uniqueByObjectKey(arr) { const obj = {}; const newArr = []; let key = ''; arr.forEach(e => { if(isNumberOrString(e)) { // 针对number与string和某些不适合当key的元素进行优化 key = e + typeof e; }else { if(e&&isObject(e)){ // 解决同key同value对象的去重 e = depthSortObject(e); } key = JSON.stringify(e) + String(e); //JSON.stringify(e)为了应对数组或对象有子内容,String(e)为了区分正则和空对象{} } if(!obj[key]) { obj[key] = key; newArr.push(e); } }); return newArr; }function isNumberOrString(e){ return typeof e === 'number' || typeof e === 'string'; }function isObject(e){ return e.constructor === Object; }function depthSortObject(obj){ if(obj.constructor !== Object){ return; } const newobj = {}; for(const i in obj){ newobj[i] = obj[i].constructor === Object ? sortObject(depthSortObject(obj[i])) : obj[i]; } return newobj; }function sortObject(obj){ const newObj = {}; const objKeys = Object.keys(obj) objKeys.sort().map((val) => { newObj[val] = obj[val]; }); return newObj; }const uniquedArr = uniqueByObjectKey(array); console.log(uniquedArr);
結果:此方法得到了「深去重*」的結果,因為我在函數中加了一些類型判斷改變key,直接暴力object[原始key]會出現number與string被捨一,而且很多類型無法成為key,寫函數過程中被JSON.stringify(/a/)坑了,還一直以為是{}的問題·~·,後來輸出所以key才發現JSON.string(/a/) === '{}',而String([]) === ”,所以得兩個都轉然後相加以避免意外。無序的,即{a:1,b:2}應該與{b:2,a:1}等價,所以深度去重把Object內部key:value都相同也進行去重)。 . ES6 Set法:
const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];function uniqueByES6Set(arr) { return Array.from(new Set(arr)) // return [...new Ser(arr)]}const uniquedArr = uniqueByES6Set(array); console.log(uniquedArr);
從結果看Array、Object、RegExp進行了保留,此方法原理是ES6的新數據結構Set,裡面存儲無序不重複數據,Set結構詳情參閱:Set與Map-阮一峰,空間複雜度O(N),時間複雜度位置,·這方法速度很快,保留複雜物件時直接用這個最好咯。 Map法:
const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];function uniqueByES6Map(arr) { const map = new Map(); return arr.filter(e => { return map.has(e) ? false : map.set(e, 'map') }) }const uniquedArr = uniqueByES6Map(array); console.log(uniquedArr);
JS陣列去重方法總結
js的陣列去重實例詳解
以上是操作js數組去重的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!