請實踐陣列扁平化 (flatten)

2022年12月30日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

陣列扁平化指的是將超過一維的陣列轉化為只有一維的陣列,目前社群中有許多效用函式庫有提供這個方法,例如知名的 lodash 函式庫就有 flattenDeep 方法來協助轉換陣列。實際例子如下,不管有幾層,通過 flattenDeep 後都會被轉換成一維陣列:

let array = [1, 2, [3, [4, 5, [6, 7, [8]]]]];

function flattenDeep(arr) {
  ...
}

const flattenArray = flattenDeep(array);

console.log(flattenArray); // [1,2,3,4,5,6,7,8]

在前端的白板面試中,很常會出現「假如沒有現成的函式庫,你會怎麼實踐陣列扁平化?」的問題。假如你還不知道要如何實踐的話,本篇文章會提出幾種方法,讓我們一起來看看吧。

方法一:flat()

其實不用透過函式庫,現在要實踐陣列扁平化,最簡單的方法是透過 JavaScript 的原生方法 — Array.prototype.flat()

flat() 方法會接受一個參數 depth,這個 depth 參數代表要扁平化的維度,如果沒有傳入任何值,預設值會是 1,最後此方法會回傳一個新陣列。要注意的一點,flat() 方法在扁平化時會忽略空格,可以看以下程式碼:

// array 是一個五維陣列
let array = [1, 2, , [3, [4, 5, [6, 7, [8]]]]];

// depth 傳入 2,最後會去除空格,結果回傳一個 3 維陣列
console.log(array.flat(2)); // [1,2,3,4,5,[6, 7, [8]]

以上方法看起來很方便,但如果不知道深度是多少,也無法做到完全扁平化。所以要如何在不知道陣列是多少維度的情況下做到扁平化?其實只要將 depth 的參數傳入 Infinity 就可以完成。

let array = [1, 2, [3, [4, 5, [6, 7, [8]]]]];

function flatten(arr) {
  return arr.flat(Infinity);
}

const flattenArray = flatten(array);
console.log(flattenArray); // [1,2,3,4,5,6,7,8]

方法二:透過遞迴的方式實踐

當然,面試官可能會追問「如果不用原生方法,你要如何自己實踐一個 flatten ?」。此時可以透過遞迴的方式來實踐。透過 for 迴圈檢查陣列中每一個項目,如果該項目是陣列,就繼續呼叫 flatten 函式;若非陣列,那就直接透過 push 方法加進新陣列中。

let array = [1, 2, [3, [4, 5, [6, 7, [8]]]]];

function flatten(arr, output = []) {
  for (const val of arr) {
    if (Array.isArray(val)) {
      flatten(val, output);
    } else {
      output.push(val);
    }
  }
  return output;
}

const flattenArray = flatten(array);
console.log(flattenArray); // [1,2,3,4,5,6,7,8]

方法三:reduce

使用 reduce 去遞迴每一層陣列,並組成一個新陣列。方法三和方法二的邏輯類似,只是在方法三透過 reduce 簡化 for 迴圈的寫法。

let array = [1, 2, [3, [4, 5, [6, 7, [8]]]]];

function flatten(arr) {
  return arr.reduce(
    (acc, cur) =>
      // 判斷目前 cur 是否為陣列,如果是陣列,則將遞迴地對該元素呼叫 flatten
      // 如果不是陣列,就直接加入到新陣列的最後一位
      Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur],
    []
  );
}

const flattenArray = flatten(array);
console.log(flattenArray); // [1,2,3,4,5,6,7,8]
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們