1. 程式人生 > >JS陣列專題2️⃣ ➖ 陣列去重

JS陣列專題2️⃣ ➖ 陣列去重

距離上次發文,已經有一段時間了,最近工作比較忙,這不眼看快雙十一了,就相當於給大家一些福利吧!

裝逼圖

一、什麼是陣列去重

簡單說就是把陣列中重複的項刪除掉,你 GET 到了嗎 ?下面我將簡單介紹下幾種基本的方法及其優缺點。

二、方法彙總

  • 兩層迴圈

** 無相同值直接 push 進新陣列,有相同的值則直接跳過本次內部迴圈 **

/*
 * @param {Array} arr    -要去重的陣列
 * @param {Array} result -初始化結果陣列
 */
const unique = (arr, result = []) => {
  const len = arr.length;
for (let i = 0; i < len; i++) { for (let j = i + 1; j < len; j++) { if (arr[i] === arr[j]) { // 相等則直接跳過 j = ++i; } } result.push(arr[i]); } return result; }

** 相同的做標記,與新陣列作比較,沒有則插入 **

/*
 * @param {Array} arr    -要去重的陣列
 * @param {Array} result -初始化結果陣列
 */
const unique = (arr, result = []) => { result.push(arr[0]); const len = arr.length; let rLen = result.length; for (let i = 1; i < len; i++) { let flag = false; for (var j = 0; j < rLen; j++) { if (arr[i] === result[j]) { flag = true; break; } }
if (!flag) { rLen++; result.push(arr[i]); } } return result; }

** 原地演算法(在陣列本身操作) **

const unique = arr => {
  const len = arr.length;
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] == arr[j]) {
        arr.splice(j,1);
        len--;
        j--;
      }
    }
  }
  return arr;
};

看似程式碼程式碼簡單,實則記憶體佔用高,不實用

  • 單層迴圈

** 物件鍵不能重複 **

const unique = (arr, result = []) => {
  const obj = {};
  const len = arr.length;
  for (let i = 0; i< len; i++) {
    if (!obj[arr[i]]) {
      // 鍵沒有,則新增
      obj[arr[i]] = 1;
      result.push(arr[i]);
    }
  }
  return result;
};

這種方法無法判斷 '1'1 等型別,解決方案:

  1. 新增判斷資料型別,比如 typeofobj[typeof arr[i] + arr[i]] 不過這還是判斷不了 ['1'][1],因為這被相加後,結果都一樣
  2. 新增 JSON.stringify() 對結果進行去格式化,這時就可以判斷了

** 排序後比較前後兩位,不相等則新增進新陣列 **

const unique = (arr, result = []) => {
  arr.sort();
  result.push(arr[0]);
  const len = arr.length;
  let rLen = result.length;
  for (let i = 1; i < len; i++) {
    if (arr[i] !== result[rLen - 1]) {
      result.push(arr[i]);
      rLen++;
    }
  }
  return result;
}

方法比較直接

** 原地演算法(排序後比較前後兩位,相等則刪除) **

const unique = (arr) => {
  arr.sort();
  let len = arr.length;
  for (let i = 1; i < len; i++) {
    if (arr[i] === arr[i - 1]) {
      arr.splice(i, 1)
      len--;
    }
  }
  return arr;
}

不消耗額外的空間

  • 偷懶的節奏

** indexOf 判斷陣列元素第一次出現的位置是否相同 **

const unique = (arr, result) => {
  arr.forEach((item, index, array) => {
    if(array.indexOf(item) === index) {
      result.push(item);
    }
  });
  return result;
}

// 使用ES6 filter
const unique = (arr) =>
  arr.filter((item, index) =>  array.indexOf(item) === index);

使用ES6 方法更簡潔效能更好

** indexOf 的ES6 方法通過 includes 判斷新陣列中是否有該元素 **

const unique = (arr, result) => {
  arr.forEach((item, index, array) => {
    if(!result.includes(item)) {
      // 或者 result.indexOf(item) === -1
      result.push(item);
    }
  });
  return result;
}

建議使用 includes

** Map 資料結構,不懂 Map 的自行解決,傳送門 **

const unique = arr => {
  const map = new Map();
  return arr.filter((item) => !map.has(item) && map.set(item, 1));
}

物件關係對映可以設定不同型別的鍵,使之很快能收集 arr 中不一樣的資料

** Set 資料結構,不允許出現重複資料,而且 Set 支援解構 傳送門 **

const unique = arr => Array.from(new Set(arr));

// 或者通過 ES6 的 ...解構
const unique = arr => [...new Set(arr)];

簡單粗暴

** reduce,給定初始值,根據陣列迴圈給出最終值 **

const unique = (arr, result = []) => arr.reduce((prev,curr) => prev.includes(curr) ? prev : [...prev, curr], result);

三、總結

方法已經說了差不多了,就看你怎麼用了,其中有一些差不多的方法,只是給了說明,沒給具體的例子,希望大家自己去試一下,告辭!