陣列去重的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"]”。