【クイズでわかる】JavaScriptの配列を平坦化する方法|flat・concat・reduceの違い

こんにちは!Reiです‎(˵ •̀ ᴗ – ˵) ✧


[[1, 2], [3, 4]] みたいな配列を、
[1, 2, 3, 4] のように1列にしたいとき、ありますよね 👀

配列を1つにまとめる平坦化のやり方は、昔からある書き方もあれば、今っぽくシンプルに書ける方法などいっぱいあるんです。


今回は、クイズ形式でJavaScriptで配列を平坦化する方法をたくさんみていきます!

やり方の違いについてぜひ注目してみてくださいね ᥫᩣ ̖́-


第1問 flat() を使うと?

まずはここから!

const nested = [[1, 2], [3, 4]];
const result = nested.flat();

console.log(result);

このコードを実行するとどうなるでしょうか?

  1. [[1, 2], [3, 4]] のまま
  2. [1, 2, 3, 4] になる
  3. エラーになる

正解は… (ここをクリック!)

2の [1, 2, 3, 4] です!


解説 !!

flat() は、配列のネストを平らにするためのメソッドです。


なので、今回のように1段だけ入れ子になっている配列なら、

[[1, 2], [3, 4]]

これがそのまま

[1, 2, 3, 4]

になります!

かなり素直な名前なので、「配列を平坦化したい」ときはまずこれを思い出せばOKです ‎(˵ •̀ ᴗ – ˵) ✧


第2問 深い配列に flat() を使うと?

次はこちら!

const nested = [[1], [[2]]];
const result = nested.flat();

console.log(result);

さて、結果はどうなるでしょうか?

  1. [1, 2]
  2. [1, [2]]
  3. [[1], [[2]]]

正解は… (ここをクリック!)

2の [1, [2]] でした!


解説 !!

ここが flat() で最初にハマりやすいポイントです 👀

flat() は、何も指定しないと 1階層だけ 平坦化します。


つまり今回は、

[[1], [[2]]]

のうち、外側の1段だけを平らにするので、

[1, [2]]

になるのです。


もしもっと深いところまでまとめて平坦化したいなら、

nested.flat(2);        // 2階層まで
nested.flat(Infinity); // すべて平坦化

といった方法で深さを指定する必要があります!


flat のポイントは、

flat() のデフォルトは1階層だけ
・深い配列は引数で深さを指定する

この2つ!覚えておいてくださいね!


第3問 concat と apply の組み合わせ

次は少し昔からある書き方についてです!

const nested = [[1, 2], [3, 4]];
const result = Array.prototype.concat.apply(???, nested);

console.log(result);

この配列を1階層だけ平坦化したいとき、apply の第1引数には何を指定するのがよいでしょうか?

  1. []
  2. {}
  3. nested

正解は… (ここをクリック!)

1の [] でした!
(applyの仕様を知ってないとちょっと難しかったかな?)


解説 !!

apply() は、配列の中身をバラバラの引数として関数に渡す ための書き方です。


つまり、

Array.prototype.concat.apply([], nested);

は、

[].concat([1, 2], [3, 4]);

のように配列の中身を1つずつ concat に渡しています。


concat() は配列同士をつなげるので、結果として1段階の平坦化ができるのです。

apply() も concat() もそれぞれ単体はシンプルな処理ですが、組み合わせることで平坦化のような処理もできるのが面白いポイントでもあります!


第4問 スプレッド構文で書くと?

次はこちら!

const nested = [[1, 2], [3, 4]];
const result = ???;

console.log(result);

スプレッド構文を使って、この配列を1階層だけ平坦化したいときの書き方はどれでしょうか?

  1. [].concat(…nested)
  2. …[].concat(nested)
  3. [].flat(…nested)

正解は… (ここをクリック!)

1の `[].concat(…nested)` でした!


解説 !!

これはさっきの apply() を、今っぽく書き直しました。

スプレッド構文 ...nested は、

[[1, 2], [3, 4]]

[1, 2], [3, 4]

のように展開して concat に渡します。


apply() よりかなり読みやすいので、もし flat() を使わずに書くならこちらのほうが見やすいですね!


第5問 reduce でつなげると?

最後の問題はこちら!

const nested = [[1, 2], [3, 4]];
const result = nested.reduce(???);

console.log(result);

[1, 2, 3, 4] の形に平坦化したいとき、reduce の中には何を書けばよいでしょうか?

  1. ((acc, val) => val.concat(acc), [])
  2. ((acc, val) => acc.push(val), [])
  3. (acc, val) => acc.concat(val), []

正解は… (ここをクリック!)

3の (acc, val) => acc.concat(val), [] です!


解説 !!

reduce() は、配列を先頭から順番に処理しながら1つの結果にまとめていくメソッドです。

reduce((acc, val) => acc.concat(val), [])

この reduce は、次の2つの引数でできています。

  • 第1引数:処理(コールバック関数)
    ・第1引数(acc):これまでにまとめた結果(累積値)
    ・第2引数(val):今処理している要素
  • 第2引数:初期値([])、最初の acc の値として使われる

なので、今回のコードでは、空の配列 [] を初期値にして、そこへ concat() で要素をどんどんつなげています。

流れとしてはこんな感じ↓

[] + [1, 2]   -> [1, 2]
[1, 2] + [3, 4] -> [1, 2, 3, 4]

少し回りくどく見えるかもしれませんが、「自分でどう結合していくかを制御したい」ときには考え方としてかなり大事な考え方なんです。

ただ、単純に平坦化したいだけなら、やっぱり flat() のほうがわかりやすいですね 👀


ここまでのポイントおさらい !!

今回の内容をまとめると、次のとおり↓

flat()

・いちばん素直で読みやすい
・デフォルトでは1階層だけ平坦化する
・深い配列は flat(2) や flat(Infinity) を使う

concat + apply

・昔からある定番の書き方
・古いコードで見かけることがある
・1階層だけ平坦化する

concat + スプレッド構文

apply() より今風で読みやすい
・考え方はほぼ同じ
・これも1階層だけ平坦化する

reduce

・結合の流れを自分で追いやすい
・応用はしやすい
・単純な平坦化だけなら少し遠回り


平坦化には、いくつか書き方があることを知っていただけたかなと思います 👀

結論としては、普段使いなら まず flat() でOK です!


ただ、

・古いコードを読む
apply() やスプレッド構文の挙動を理解したい
reduce() で配列操作の流れを掴みたい

みたいな場面では、他の書き方を知っているとちゃんと役立ちます 💡


最後に

同じ平坦化でも、書き方によって見え方や考え方が変わるのが面白いところ!

平坦化に限らず、いろんな方法を知っていると、コードを読むときにも書くときにも選択肢が増えて一気にプログラミングの深さを感じられるかなってと思います‎(˵ •̀ ᴗ – ˵) ✧

この記事が役に立ったら嬉しいです ᥫᩣ ̖́-

コメント

タイトルとURLをコピーしました