1. 程式人生 > >JavaScript 陣列去重的多種方法原理詳解

JavaScript 陣列去重的多種方法原理詳解

說明

陣列去重,這是一個面試經常會遇見的問題,網上講陣列去重的文章也是特別的多,但是我們依舊來講講陣列去重,這篇文章比較適合於接觸過一段時間的JavaScript的初學者,希望這篇文章能給初學者帶來一些幫助。

方法一

function unique(arr)
{
    var result = []; //結果陣列
    for(var i = 0; i < arr.length; i++) 
    {
        //如果在結果陣列result中沒有找到arr[i],則把arr[i]壓入結果陣列result中
        if (result.indexOf(arr[i]) == -1
) result.push(arr[i]); } return result; }

方法二

Array.prototype.unique = function()
{
    var result = [this[0]]; //結果陣列
    for(var i = 1; i < this.length; i++) //從第二項開始遍歷
    {
        //如果呼叫unique()方法的陣列的第i項在陣列中第一次出現的位置是i,
        //那麼表示第i項是不重複的,則存入結果陣列
        if (this.indexOf(this[i]) == i) result.push(this
[i]); } return result; }

解釋
方法一和方法二,看第一眼,可能沒什麼,等你把兩個方法弄明白,才發現區別真的不大,就像是同一個人只是換了件衣服而已。
好吧,我們看看這個人是誰,要說這個人是誰,重點在於for迴圈、indexOf( )方法和push( )方法。
for迴圈就不必多做解釋了,既然接觸過JavaScript一定是明白的
在Array 物件中
indexOf( )方法搜尋陣列中的元素,並返回它首次出現的位置,如果沒找到則返回 -1。
在String 物件中
indexOf( ) 方法可返回某個指定的字串值在字串中首次出現的位置,如果沒找到則返回 -1。
注意:
JavaScript中的Array物件 和 String物件都是具有indexOf( )方法的,而且用法是一樣的。
對於indexOf( )不是很理解的朋友

點這裡

push( ) 方法可向陣列的末尾新增一個或多個元素,並返回新的長度。
push( )方法是Array物件中的方法,String物件中沒有。
對於push( )不是很理解的朋友點這裡

那衣服是什麼呢?我們繼續說,方法一,是定義了一個函式unique,傳入的引數沒有限制,也就是說,不管是誰都可以用這個方法,看圖
這裡寫圖片描述
陣列能用這個方法,字串也能用這個方法。
而方法二是在Array物件中添加了一個unique( )方法,這樣的話,就只能是陣列才能用這個方法了,看圖
這裡寫圖片描述
用字串去呼叫這個方法,報錯了,因為字串沒有這個方法,只有陣列有,這樣就多了一種限制。

方法三

function unique3(arr){
    //遍歷arr,同時建立結果陣列result
    for(var i=0,result=[];i<arr.length;i++){
    //遍歷結果陣列result
        for(var j=0;j<result.length;j++){
            //如果result中有一個元素等於arr[i],就退出迴圈
            //說明arr[i],是一個重複的元素
            if(result[j]===arr[i]){break;}
        }//遍歷結束
        //如果j等於result的length,就把arr[i],壓入陣列result
        //j等於result的length,說明遍歷到了最後,也就是沒有找到相同的元素
        if(j===result.length){
                result[result.length]=arr[i];
        }
    }
    return result;//返回result
}

方法四

Array.prototype.unique4 = function(){
     //建立結果陣列,值為呼叫unique4()方法的陣列的第一個元素
     var result = [this[0]];
     //遍歷 呼叫unique4方法的陣列
     for(var i = 1; i < this.length; i++){
          //宣告一個變數 repeat,判斷元素是不是重複
          var repeat = false;
          //遍歷結果陣列 result
          for(var j = 0; j < result.length; j++){
            //如果結果陣列result中的一個元素,等於,呼叫unique4()方法的陣列的其中一個元素,repeat值為true,跳出迴圈
            //也就是結果陣列result中的這個元素和呼叫unique4()方法的陣列中的元素重複了
           if(this[i] === result[j]){
            repeat = true;
            break;
           }
          }
          //如果結果陣列result中的一個元素,不等於,呼叫unique4()方法的陣列的其中一個元素,repeat值為false,把元素新增到結果陣列
          //也就是結果陣列result中的這個元素和呼叫unique4()方法的陣列中的元素不重複
          if(!repeat){
           result.push(this[i]);
          }
     }
//   返回結果陣列result
     return result;
}

解釋
我相信,你已經看出來了,方法三和方法四的區別也不大,能明白其中一個,另外的也一樣!這兩個方法,看上去程式碼挺多,你可以去掉註釋看看,其實也不多,主要的就是兩層for迴圈罷了,而內層的for迴圈其實是實現了一下indexOf( )的功能。

方法五

function unique5(arr){
// 建立結果陣列
 var result = [];
 //建立hash物件,用來代替indexOf
 var hash = {};
 for(var i = 0; i < arr.length; i++){
  //key就是陣列元素的型別+陣列元素,用來區分number和"number"
  var key = typeof(arr[i]) + arr[i];
  //如果hash物件中的key屬性值不等於1(說明hash物件中不存在key屬性),就把arr[i]壓入結果陣列result,同時設定hash的key屬性值為1
  if(hash[key]!==1){
      result.push(arr[i]);
      hash[key] = 1;
    }
 }
 return result;
}

方法六

Array.prototype.unique6=function(){
     // 建立結果陣列
     var result = [];
     //建立hash物件,用來代替indexOf
     var hash = {};
     for(var i=0;i<this.length;i++){
        // hash[this[i]] ,這是看 hash 中是否有 this[i] 這個屬性,如果有,該屬性值就+1,這個值就是出現的次數
        if(hash[this[i]]){
             hash[this[i]]++;
        }
        //如果,hash中沒有this[i]屬性,則將this[i]壓入結果陣列result,同時給這個屬性,賦值為1
        else{
             result.push(this[i]);
             hash[this[i]]=1;
        }
     } 
//最後返回了一個物件,包括了結果陣列,和帶次數的hash物件  
return {result,hash};
}

解釋
好吧,方法五和方法六差不多,核心思想和前面的幾種方法一樣,但是還是有一些不同的,方法五中寫var key = typeof(arr[i]) + arr[i];這句是因為在 JavaScript 裡,物件的鍵只能是字串,所以為了區分陣列中的數字,和能轉為數字的字串,就需要這句了,而方法六就不能區分了,看圖
這裡寫圖片描述

方法七

Array.prototype.unique7 = function(){
    //先排序
    this.sort(); 
    //建立結果陣列
    var result = [this[0]];
    /* 遍歷 呼叫unique7()方法的陣列 如果該陣列中的第i項,
    不等於結果陣列result中的最後一項,就把第i項,壓入結果陣列 */
    for(var i = 1; i < this.length; i++){
        if(this[i] !== result[result.length - 1]){
            result.push(this[i]);
        }
    }
    return result;
}

解釋
這次終於是不一樣了,思路已經換了,這次需要先把陣列排序,這點很重要,排序之後,再進行比較,比較的是,呼叫方法的陣列和結果陣列,其實也就是在比較呼叫方法的陣列中的,第i項和第i-1項,如果相等,就什麼都不做,不相等就把第i項壓入結果陣列。

總結

這裡這些方法我比較推薦用 方法五 和 方法七。
如果你認同這七種方法,可以算是解決陣列去重問題的方法,那麼我相信,你可以寫出更多的方法來,如果你覺得這裡很多的方法的思路是一樣的,只能算是兩種方法,我也同意。
如果你覺得這些方法太麻煩,看這裡
JavaScript陣列去重—ES6的兩種方式
這篇文章中的方法可能更適合你哦!
如果你還有什麼更有趣方法,也歡迎分享出來。