请实践数组扁平化 (flatten)

2022年12月30日

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

数组扁平化指的是将超过一维的数组转化为只有一维的数组,目前社群中有许多效用函式库有提供这个方法,例如知名的 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 上追蹤我們