數組去重

JavaScript學習筆記:數組去重

 

話說面試常會碰到面試官會問JavaScript實現數組去重的問題,整理了一些有關於JavaScript數組去重的方法。下面這些數組去重的方法是本身收集和整理的。javascript

雙重循環去重

這個方法使用了兩個for循環作遍歷。整個思路是:html

  • 構建一個空數組用來存放去重後的數組
  • 外面的for循環對原數組作遍歷,每次從數組中取出一個元素與結果數組作對比
  • 若是原數組取出的元素與結果數組元素相同,則跳出循環;反之則將其存放到結果數組中

代碼以下:java

 1 Array.prototype.unique1 = function () {
 2     // 構建一個新數組,存放結果
 3     var newArray = [this[0]];
 4     // for循環,每次從原數組中取出一個元素
 5     // 用取出的元素循環與結果數組對比
 6     for (var i = 1; i < this.length; i++) {
 7         var repeat = false;
 8         for (var j=0; j < newArray.length; j++) {
 9             // 原數組取出的元素與結果數組元素相同
10             if(this[i] == newArray[j]) {
11                 repeat = true;
12                 break;
13             }
14         }
15         if(!repeat) {
16             // 若是結果數組中沒有該元素,則存放到結果數組中
17             newArray.push(this[i]);
18         }
19     }
20     return newArray;
21 }

 

假設咱們有一個這樣的數組:node

1 var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1',`2`];
2 
3 arr.unique1(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5]

 

聽說這種方法比較耗時,費性能。簡單作個測試(測試方法寫得比較拙逼):面試

 1 function test () {
 2     var arr = [];
 3     for (var i = 0; i < 1000000; i++) {
 4         arr.push(Math.round(Math.random(i) * 10000));
 5     }
 6     doTest(arr, 1);
 7 }
 8 function doTest(arr, n) {
 9     var tStart = (new Date()).getTime();
10     var re = arr.unique1();
11     var tEnd = (new Date()).getTime();
12     console.log('雙重循環去重方法使用時間是:' + (tEnd - tStart) + 'ms');
13     return re;
14 }
15 test();

 

在Chrome控制器運行上面的代碼,測試雙重循環去重所費時間:11031ms算法

上面的方法能夠使用forEach()方法和indexOf()方法模擬實現:數組

1 function unique1() {
2     var newArray = [];
3     this.forEach(function (index) {
4         if (newArray.indexOf(index) == -1) {
5             newArray.push(index);
6         }
7     });
8     return newArray;
9 }

 

經過unique1.apply(arr)unique1.call(arr)調用。不過這種方法效率要快得多,一樣的上面測試代碼,所費時間5423ms,幾乎快了一半。app

排序遍歷去重

先使用sort()方法對原數組作一個排序,排完序以後對數組作遍歷,而且檢查數組中的第i個元素與結果數組中最後一個元素是否相同。若是不一樣,則將元素放到結果數組中。dom

 1 Array.prototype.unique2 = function () {
 2     // 原數組先排序
 3     this.sort();
 4     // 構建一個新數組存放結果
 5     var newArray = [];
 6     for (var i = 1; i < this.length; i++) {
 7         // 檢查原數中的第i個元素與結果中的最後一個元素是否相同
 8         // 由於排序了,因此重複元素會在相鄰位置
 9         if(this[i] !== newArray[newArray.length - 1]) {
10             // 若是不一樣,將元素放到結果數組中
11             newArray.push(this[i]);
12         }
13     }
14     return newArray;
15 }

 

例如:性能

1 var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2'];
2 arr.unique2(); // ["1", 1, 2, "2", 3, 32, 34, 4, 5, 56, "a", "b", "c"]

 

這種方法有兩個特點:

  • 去重後的數組會作排序,主要是由於原數在去重前作了排序
  • 去重後的數組,與數字相同的數字字符沒法區分,好比'1'1

使用一樣的方法,測試所費時間:1232ms

對象鍵值對法

這種去重方法實現思路是:

  • 建立一個JavaScript對象以及新數組
  • 使用for循環遍歷原數組,每次取出一個元素與JavaScript對象的鍵作對比
  • 若是不包含,將存入對象的元素的值推入到結果數組中,而且將存入object對象中該屬性名的值設置爲1

代碼以下:

 1 Array.prototype.unique3 = function () {
 2     // 構建一個新數組存放結果
 3     var newArray = [];
 4     // 建立一個空對象
 5     var object = {};
 6     // for循環時,每次取出一個元素與對象進行對比
 7     // 若是這個元素不重複,則將它存放到結果數中
 8     // 同時把這個元素的內容做爲對象的一個屬性,並賦值爲1,
 9     // 存入到第2步創建的對象中
10     for (var i = 0; i < this.length; i++){
11         // 檢測在object對象中是否包含遍歷到的元素的值
12         if(!object[typeof(this[i]) + this[i]]) {
13             // 若是不包含,將存入對象的元素的值推入到結果數組中
14             newArray.push(this[i]);
15             // 若是不包含,存入object對象中該屬性名的值設置爲1
16             object[typeof(this[i]) + this[i]] = 1;
17         }
18     }
19     return newArray;
20 }

 

運行前面的示例:

1 var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2'];
2 arr.unique3(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]

 

一樣的,不一樣的鍵可能會被誤認爲同樣;例如: a[1]a["1"] 。這種方法所費時間:621ms。 這種方法所費時間是最短,但就是佔用內存大一些。

除了上面幾種方法,還有其餘幾種方法以下:

 1 // 方法四
 2 Array.prototype.unique4 = function () {
 3     // 構建一個新數組存放結果
 4     var newArray = [];
 5     // 遍歷整個數組
 6     for (var i = 0; i < this.length; i++) {
 7         // 遍歷是否有重複的值
 8         for (j = i + 1; j < this.length; j++) {
 9             // 若是有相同元素,自增i變量,跳出i的循環
10             if(this[i] === this[j]) {
11                 j = ++i;
12             }
13         }
14         // 若是沒有相同元素,將元素推入到結果數組中
15         newArray.push(this[i]);
16     }
17     return newArray;
18 }

 

Chrome測試結果

1 var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2'];
2 arr.unique4(); // ["a", 1, 3, 4, 56, 32, 34, 2, "b", "c", 5, "1", "2"]

 

一樣的,1'1'沒法區分。

 1 // 方法五
 2 Array.prototype.unique5 = function () {
 3     // 構建一個新數組存放結果
 4     var newArray = [];
 5     // 遍歷整個數組
 6     for (var i = 0; i < this.length; i++) {
 7         // 若是當前數組的第i值保存到臨時數組,那麼跳過
 8         var index = this[i];
 9         // 若是數組項不在結果數組中,將這個值推入結果數組中
10         if (newArray.indexOf(index) === -1) {
11             newArray.push(index);
12         }
13     }
14     return newArray;
15 }

 

Chrome測試結果:

1 var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2'];
2 arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]

 

一樣的,相似於1'1'沒法區分。所費時間:14361ms

// 方法六
Array.prototype.unique6 = function () {
    return this.reduce(function (newArray, index) {
        if(newArray.indexOf(index) < 0) {
            newArray.push(index);
        }
        return newArray;
    },[]);
}

 

測試結果以下:

1 var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2'];
2   arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]

 

所費時間:16490ms

1     // 方法七
2 Array.prototype.unique7 = function(){
3     var newArray;
4     newArray = this.filter(function (ele,i,arr) {
5         return arr.indexOf(ele) === i;
6     });
7     return newArray;
8 }

 

測試結果:

1   var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2'];
2   arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]

所費時間:13201ms

方法雖然不少種,但相比下來,下面這種方法是較爲優秀的方案:

 1 Array.prototype.unique3 = function () {
 2     // 構建一個新數組存放結果
 3     var newArray = [];
 4     // 建立一個空對象
 5     var object = {};
 6     // for循環時,每次取出一個元素與對象進行對比
 7     // 若是這個元素不重複,則將它存放到結果數中
 8     // 同時把這個元素的內容做爲對象的一個屬性,並賦值爲1,
 9     // 存入到第2步創建的對象中
10     for (var i = 0; i < this.length; i++){
11         // 檢測在object對象中是否包含遍歷到的元素的值
12         if(!object[typeof(this[i]) + this[i]]) {
13             // 若是不包含,將存入對象的元素的值推入到結果數組中
14             newArray.push(this[i]);
15             // 若是不包含,存入object對象中該屬性名的值設置爲1
16             object[typeof(this[i]) + this[i]] = 1;
17         }
18     }
19     return newArray;
20 }

但在ES6去重還有更簡單,更優化的方案,好比:

1 // ES6
2 function unique (arr) {
3     const seen = new Map()
4     return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
5 }
6 // or
7 function unique (arr) {
8     return Array.from(new Set(arr))
9 }

參考資料

相關文章
相關標籤/搜索