數組去重的7種算法


參考《javascript種難點實例精講》

1. 遍歷數組

算法1的主要思想是在函數內部新建一個數組,對傳入的數組進行遍歷。如果遍歷的值不在新數組中就添加進去,如果已經存在就不做處理。

function arrayUnique(array) {
   var result = [];
   for (var i = 0; i < array.length; i++) {
       if(result.indexOf(array[i]) === -1) {
           result.push(array[i]);
       }
   }
   return result;
}
var array = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique(array));

以上代碼在運行后得到的結果為“[1, 4, 5, 7, 8, 10]”。

2. 利用對象鍵值對

算法2的主要思想是新建一個JS對象以及一個新的數組,對傳入的數組進行遍歷,判斷當前遍歷的值是否為JS對象的鍵。如果是,表示該元素已出現過,則不做處理;如果不是,表示該元素第一次出現,則給該JS對象插入該鍵,同時插入新的數組,最終返回新的數組。

function arrayUnique2(array) {
   var obj = {}, result = [], val, type;
   for (var i = 0; i < array.length; i++) {
       val = array[i];
       if (!obj[val]) {
           obj[val] = 'yes';
           result.push(val);
       }
   }
   return result;
}
var array = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique2(array));

上面的代碼存在些許缺陷,即不能判斷Number類型和String類型的數字。因為不管是Number類型的1,還是String類型的"1",作為對象的key都會被當作先插入類型的1處理。所以會把Number類型和String類型相等的數字作為相等的值來處理,但實際上它們並非是重復的值。
對於數組[1, 4, 5, 7, 4, 8, 1, 10, 4, '1']的處理結果為“[1, 4, 5, 7, 8, 10]”,這顯然是不合理的,正確結果應為“[1, 4, 5, 7, 8, 10, '1']”。
為了解決這個問題,我們需要將數據類型作為key的value值。這個value值為一個數組,判斷key的類型是否在數組中,如果在,則代表元素重復,否則不重復,並將數據類型push到value中去。
根據以上分析,得到以下代碼,其中obj為鍵值對象,result為最終返回結果

function arrayUnique2(array) {
   var obj = {}, result = [], val, type;
   for (var i = 0; i < array.length; i++) {
       val = array[i];
       type = typeof val;
       if (!obj[val]) {
           obj[val] = [type];
           result.push(val);
       } else if (obj[val].indexOf(type) < 0) {   // 判斷數據類型是否存在 
           obj[val].push(type);
           result.push(val);
       }
   }
   return result;
}
var array2 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique2(array2));

以上的代碼運行后得到的結果為“[1, 4, 5, 7, 8, 10, '1']”,可以發現1與'1'不為重復的元素,滿足實際情況。

3. 先排序,再去重

算法3的主要思想是借助原生的sort()函數對數組進行排序,然后對排序后

的數組進行相鄰元素的去重,將去重后的元素添加至新的數組中,返回這個新數組。
根據以上分析,得到以下代碼

function arrayUnique3(array) {
   var result = [array[0]];
   array.sort(function(a,b){return a-b});
   for (var i = 0; i < array.length; i++) {
       if (array[i] !== result[result.length - 1]) {
           result.push(array[i]);
       }
   }
   return result;
}
var array3 = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique3(array3));

以上代碼的運行結果為“[1, 4, 5, 7, 8, 10]”。

4. 優先遍歷數組
算法4的主要思想是利用雙層循環,分別指定循環的索引i與j,j的初始值為i+1。在每層循環中,比較索引i和j的值是否相等,如果相等則表示數組中出現了相同的值,則需要更新索引i與j,操作為++i;同時將其賦值給j,再對新的索引i與j的值進行比較。循環結束后會得到一個索引值i,表示的是右側沒有出現相同的值,將其push到結果數組中,最后返回結果數組。
根據以上的分析,得到以下的代碼

function arrayUnique4(array) {
   var result = [];
   for (var i = 0, l = array.length; i < array.length; i++) {
       for (var j = i + 1; j < l; j++) {
            // 依次與后面的值進行比較,如果出現相同的值,則更改索引值
            if (array[i] === array[j]) {
                j = ++i;
            }
       }
       // 每輪比較完畢后,索引為i的值為數組中只出現一次的值
       result.push(array[i]);
   }
   return result;
 }
var array4 = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique4(array4));

以上代碼的運行結果為“[1, 4, 5, 7, 8, 10]”。

5. 基於reduce()函數
算法5的主要思想是利用reduce()函數,類似於算法2,需要借助一個key-value對象。在reduce()函數的循環中判斷key是否重復,如果為是,則將當前元素push至結果數組中。實際做法是設置initialValue為一個空數組[],同時將initialValue作為最終的結果進行返回。在reduce()函數的每一輪循環中都會判斷數據類型,如果數據類型不同,將表示為不同的值,如1和"1",將作為不重復的值。
根據以上的分析,得到以下的代碼

function arrayUnique5(array) {
   var obj = {}, type;
   return array.reduce(function (preValue, curValue) {
       type = typeof curValue;
       if (!obj[curValue]) {
           obj[curValue] = [type];
           preValue.push(curValue);
       } else if (obj[curValue].indexOf(type) < 0) {   // 判斷數據類型是否存在
            obj[curValue].push(type);
           preValue.push(curValue);
       }
       return preValue;
   }, []);
}
var array5 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique5(array4));

以上代碼的運行結果為“[1, 4, 5, 7, 8, 10, "1"]”

6. 借助ES6的Set數據結構

算法6的主要思想是借助於ES6中新增的Set數據結構,它類似於數組,但是有一個特點,即成員都是唯一的,所以Set具有自動去重的功能。
在ES6中,Array類型增加了一個from()函數,用於將類數組對象轉化為數組,然后再結合Set可以完美實現數組的去重。
根據以上的分析,得到以下的代碼。

function arrayUnique6(array) {
   return Array.from(new Set(array));
}
var arr6 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique6(arr6));

以上代碼的運行結果為“[1, 4, 5, 7, 8, 10, "1"]”。

7. 借助ES6的Map數據結構

算法7的主要思想是借助於ES6中新增的Map數據結構,它是一種基於key-value存儲數據的結構,每個key都只對應唯一的value。如果將數組元素作為Map的key,那么判斷Map中是否有相同的key,就可以判斷出元素的重復性。
Map還有一個特點是key會識別不同數據類型的數據,即1與"1"在Map中會作為不同的key處理,不需要通過額外的函數來判斷數據類型。
基於Map數據結構,通過filter()函數過濾,即可獲得去重后的結果。
根據以上的分析,得到以下的代碼。

function arrayUnique7(array) {
   var map = new Map();
   return array.filter((item) => !map.has(item) && map.set(item, 1));
}
var arr7 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique7(arr7));

以上代碼的運行結果為“[1, 4, 5, 7, 8, 10, "1"]”。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM