js數(shù)組去重是前端面試中經(jīng)常被問的題目,考察了面試者對js的掌握,解決問題的思路,以及是否具有專研精神。曾經(jīng)一位前端界大神告訴我,解決問題的方式有很多種,解決問題時多問問自己還有沒有其他的方法,探求最優(yōu)解決方案才能學(xué)到更多。


方案一

 /**
   * 1.構(gòu)建一個新數(shù)組
   * 2.遍歷目標(biāo)數(shù)組,依次取出每一個元素
   * 3.將取出的元素與新數(shù)組里面的所有元素進行比較,
   *    如果沒有出現(xiàn) -> 該元素添加到新數(shù)組中,
   *    如果出現(xiàn)  -> 處理下一個目標(biāo)數(shù)組元素
   * */
  function distinct(arr) {
    console.time();    //跟蹤方法的占用時長
    var result = [];    // 構(gòu)建結(jié)果數(shù)組result
    for (var i = 0, len = arr.length; i < len; i++) {
      for (var j = 0, rlen = result.length; j <= rlen; j++) {
        if (arr[i] === result[j]) {
          break;
        }
        if (j == result.length) {
          result.push(arr[i]);
        }
      }
    }
    console.timeEnd();
    return result;
  }
方案優(yōu)點:
  • 結(jié)果數(shù)組與目標(biāo)數(shù)組的順序保持一致
  • 思路簡單,兼容性好
方案缺點:
  • 速度慢

方案二

/**
   *1.目標(biāo)數(shù)組排序
   *2.遍歷目標(biāo)數(shù)組,檢測數(shù)組中的第i 個元素與結(jié)果數(shù)組中最后一個元素是否相同,如果不同,則將該元素添加到結(jié)果數(shù)組中
   * */
  function distinct(arr) {
    console.time();
    var result = [];
    arr = arr.sort();
    for (var i = 0, len = arr.length; i < len; i++) {
      if (arr[i] !== result[result.length - 1]) {
        result.push(arr[i])
      }
    }
    console.timeEnd();
    return result;
  }
方案優(yōu)點:
  • 方案中先排序,后遍歷,速度比方法一快
方案缺點:
  • 方案中使用了數(shù)組排序sort,打亂了原有順序

Tips:數(shù)組排序

js中提供了數(shù)組排序方法sort,使用時需要注意以下幾點:

  1. 調(diào)用sort方法時改變了目標(biāo)數(shù)組本身,非生成新數(shù)組
  2. sort方法默認按照字符順序進行排序,不過提供了回調(diào)方法,可以自定義排序規(guī)則

現(xiàn)有一數(shù)組arr:1,11,23,56,3,4,5,7,562,67

按字符排序
arr.sort() // 1, 11, 23, 3, 4, 5, 56, 562, 67, 7
按數(shù)字大?。赫?/h5>
arr.sort((a,b) => a-b) // 1, 3, 4, 5, 7, 11, 23, 56, 67, 562
按數(shù)字大?。旱剐?/h5>
arr.sort((a,b) => b-a) // 562, 67, 56, 23, 11, 7, 5, 4, 3, 1

方案三

/**
   * 利用ES6的 數(shù)據(jù)結(jié)構(gòu)SET的無重復(fù)值特性
   * Array.from 將類數(shù)組轉(zhuǎn)換成數(shù)組
   * */
  function distinct3(arr) {
    console.time();
    var result = Array.from(new Set(arr));
    console.timeEnd();
    return result;
  }
方案優(yōu)點:
  • 代碼簡潔,執(zhí)行速度快
方案缺點:
  • ES6語法,使用時需要考慮兼容性問題

方案四

 /**
   * 利用對象屬性無重復(fù)的特點
   * 遍歷目標(biāo)數(shù)組,將值設(shè)置為對象屬性
   * Object.keys 將對象的所有屬性提取成一個數(shù)組
   * */
  function distinct(arr) {
    console.time();
    var result = {};
    for (var i = 0, len = arr.length; i < len; i++) {
      result[arr[i]] = '';
    }
    result = Object.keys(result);
    console.timeEnd();
    return result;
  }
方案優(yōu)點:
  • 速度快
方案缺點:
  • 1 與 '1' 無法區(qū)分
  • 結(jié)果數(shù)組中的值全部為字符串
  • 占內(nèi)存,相當(dāng)于利用空間換時間

方案五

/**
   * Array.filter 數(shù)組過濾函數(shù),只保留符合條件的值
   * indexOf 查找元素第一次出現(xiàn)的位置,所有第1次之后查找的元素位置都不符合條件
   * */
  function distinct(arr) {
    console.time();
    var result = arr.filter(function (elem, index, self) {
      return self.indexOf(elem) === index;
    });
    console.timeEnd();
    return result;
  }

測試

隨機生成包含10000個數(shù)字的數(shù)組

function random() {
    var a = [];
    for (var i = 0; i < 10000; i++) {
      a.push(Math.ceil(i * Math.random()))
    }
    return a;
  }

現(xiàn)在執(zhí)行上述去重方法,取5次測試結(jié)果的平均值:

  方法一 方法二 方法三 方法四 方法五
第一次 91.281 7.921 4.36 2.038 68.856
第二次 104.492 7.519 2.267 1.328 70.555
第三次 105.937 8.874 1.804 1.680 73.020
第四次 100.524 5.287 2.602 1.573 85.129
第五次 106.612 8.990 1.615 1.963 79.115
平均 101.769 7.718 2.529 1.716 75.335

從執(zhí)行速度來看,方法四 < 方法三 < 方法二 < 方法五 < 方法一
方法四最快,方法一最慢。但是五種方法各有優(yōu)缺點,使用時要根據(jù)實際情況選擇適合的方案。