JS- 數組去重方法整理

indexOf數組

簡單並且能夠加中文,可是兼容性很差,indexOF兼容到ie9數據結構

 1 function uniq(arr) {
 2     var temp = [];
 3     for (let i = 0; i < arr.length; i++) {
 4         if (temp.indexOf(arr[i]) == -1) {
 5             temp.push(arr[i])
 6         }
 7     }
 8     return temp;
 9 }
10 console.log(uniq([1, 2, 3, 2, 34, "a", "b", "a", 2, 5, 2, 62, ]));

 

【排序後相鄰去除法】spa

簡單,去重排序一塊兒作。但必須是純數組,不能在數字中混入字符串prototype

 1 function uniq3(array) {
 2   array.sort((a, b) => {
 3     return a - b
 4   });
 5   var temp = [array[0]]; //關鍵點,先把第一個放進去
 6   for (let i = 1; i < array.length; i++) { //i從1開始
 7     if (array[i] !== temp[temp.length - 1]) {
 8       temp.push(array[i])
 9     }
10   }
11   return temp;
12 }
13 console.log(uniq3([1, 2, 1, 2, 12, 13, 235, 3])); // 缺點就是不能加入字符串
14 console.log(uniq3([1, 2, "b", 1, 2, 12, 13, 235, 3, "a"])); // 缺點就是不能加入字符串

 

 

【根據上邊改爲數組中字符串排序去重法】3d

 1 function uniq4(array) {
 2   array.sort((a, b) => {
 3     return (a+'').charCodeAt() - (b+'').charCodeAt()
 4   });
 5   var temp = [array[0]]; //關鍵點,先把第一個放進去
 6   for (let i = 1; i < array.length; i++) { //i從1開始
 7     if (array[i] !== temp[temp.length - 1]) {
 8       temp.push(array[i])
 9     }
10   }
11   return temp;
12 }
13 console.log(uniq4(['w', 'a', "b", 'w', 'n', 's', 's', 'b', 'e', "a"])); // 缺點就是不能混入別的

 

【存到對象裏一一對比,去重無排序】code

 

思路 - 利用對象的hash鍵值對方法,快速獲取的特色對象

準備一個對象和一個新數組,blog

循環原數組時,將數組的值當作對象的鍵,且對應值爲true/1皆可),排序

而後每次拿原數組的下一個值都去判斷一下對象中是否有這個值,字符串

沒有再push到新數組中去,最後返回新數組。

 1 uniqArr: function (arr) {
 2     var arr = Array.prototype.slice.call(arr),//這裏防止僞數組,容錯
 3         obj = {},
 4         newArr = [];
 5         obj[arr[0]] = true;//這裏不必
 6         newArr.push(arr[0]);
 7     arr.forEach((el) => {
 8         if (!obj[el]) {//可是這樣寫,又一個問題,見下邊總結
 9             obj[el] = true;//這裏寫成true,if裏少一步隱式轉換
10             newArr.push(el);
11         }
12     });
13     return newArr;
14 }

 

總結:

 

這種寫法有一個問題,就是當咱們arr中有多個不同的對象元素(好比[1,{val:212},'a',{c: 1},false,{d:2}]這樣時,會發現,只留下了第一個對象{val:212}這樣。

 

控制檯效果:

 

這是由於一個對象值當作obj的鍵名時會被toString化,獲得的是obj['[object Object]'],後邊再有對象時在forEach判斷裏條件不會成立,就不會被push到新數組,所以也就會被過濾掉了。

 

其原理同這個題:

1 var a = {};b = {m: 1};c ={n:2};
2 
3 a[b] = 'b';
4 
5 a[c] = 'c';

a當中,鍵名不叫b也不叫c,而是b這個對象被Object.prototype.toString化後的字符串[object Object]。就是同一個原理。

 

由於咱們使用[]來給對象a追加屬性,在[]中,是指望是一個字符串類型的值,因此裏邊的值會被"字符串化"

 

也就是當咱們傳的變量是一個{}時,對象會調用自身原型上的Object.prototype.toString進行轉化變成字符串[object Object]

 

當咱們變量是一個數字12,會調用數字的構造類Number原型上重寫的toString方法獲得一個字符串'12'

 

反正都是會轉成字符串。即便當變量轉爲字符串後爲特殊值(如NaN)等也不例外:

 

 

以上邊的缺點引出下邊的方法:

  

【一行代碼實現數組去重】

1 let newArr = [...new Set([1, 2, 23, 1, "gjf", 1, 6, "gjf","gfj"])]
2 console.log(newArr)

// 核心

[…new Set([..須要去重的數組..])]

 

 

【缺點方法的解決】

 

上邊說道【存到對象裏,一一對比進行去重】方法時,有一個缺點是數組內嵌套了對象、數組這些值時,

 

由於obj[鍵值]會被字符串化,致使後邊出現的多個對象都會被當作重複處理,

 

因此咱們須要在往obj裏存值時對這種狀況進行一下處理

 

須要去重的數組:

 

先看最初的寫法:

 1 function uniq0517(arr){
 2     var obj = {};
 3     var rst = [];
 4     arr.forEach(el => {
 5         if(!obj[el]){
 6             obj[el] = true;
 7             rst.push(el);
 8         }
 9     });
10     console.log(obj);// 注意下打印的obj
11     return rst;
12 }

目標:去掉重複的對象和數組以及其餘原始值,可是保留不一樣的對象和數組.

 

去重後的結果:

 

 

觀察發現,除了對象外,都完成了很好的效果。

 

看打印的obj結果分析問題:

 

由於數組在obj的中括號[]裏進行toString後是字符串'1,23,4'這樣,因此能夠比較不一樣。

 

可是對象不行。對象一概是[object Object]這樣,須要對對象進行處理:

 

個人思路是,若是檢測值爲對象(就是普通的對象,而不是時間、正則等這種對象,

 

因此須要toString檢測)時,就把這個對象先JSON.stringify化了。再去進行對比。

 

就像下面這樣,JSON.stringify事後的對象絕對能夠判斷是否全等。

 

 

所以數組去重改造事後的代碼以下:

 1 function uniq0517(arr){
 2     var obj = {},
 3         rst = [],
 4         tempEl = '';
 5     arr.forEach(el => {
 6         if(Object.prototype.toString.call(el) === '[object Object]'){
 7             // 證實這個值是一個對象,就事先將對象字符串化。而不是讓他調用本身的toString
 8             tempEl = JSON.stringify(el);
 9         }else{
10             // 其餘類型的值時不作改變
11             tempEl = el;
12         }
13         if(!obj[tempEl]){
14             obj[tempEl] = true;
15             rst.push(el);
16         }
17     });
18     console.log(obj);
19     return rst;
20 }

 

完美通過檢驗!

 

 

最後拓展,想着把臨時obj換成Map數據結構改造一下:

 

 1 function uni10519(arr){
 2     // 用Map實現去重 - 但凡引用值都不能去重
 3     let map = new Map(),
 4         rst = [];
 5     arr.forEach(el => {
 6         if(!map.get(el)){// 已有的一個對象再獲取,由於地址不一樣,因此獲得false
 7             map.set(el,true);
 8             rst.push(el);
 9         }
10     });
11     console.log(map);
12     return rst;
13 }
14 console.log('map試水失敗',uni10519(arr20190517));

算了吧。。。引用值地址不一樣,無法取出來做對比。

 

一樣的,對於這種超級複雜類型的數組,進行去重的話,還得用我最原始的方式進行一一比對。不然set也撲街了:

1 function uni10519Set(arr) {
2     // 用Set實現去重 
3     return [...new Set(arr)];
4 }
5 console.log('set試水失敗',uni10519Set(arr20190517));// 對象、數組什麼的引用值都不能比較相等
相關文章
相關標籤/搜索