【JavaScript】flatMapメソッドの使い方!flatやmapとの違いは?

ES2019で追加されたflatMapメソッドは、配列の要素を変換しつつ、ネストされた配列をフラット化するメソッドです。初めてflatMapメソッドを見たときに、「これってmapメソッドと何が違うの?」と思う方も多いと思います。

本記事では、flatMapメソッドについて、以下の内容をサンプルコードを用いてわかりやすく解説します。

  • flatメソッドとは
  • flatMapメソッドとは
  • flatメソッドとflatMapメソッドの違い
  • flatMapメソッドの構文
  • flatMapメソッドの使い方
    • 配列の要素を増やす
    • 配列の要素を削除する
    • 文字列を分割してフラットにする
    • 配列の要素の重複を除去する
    • APIレスポンスのネストされたデータをフラット化する

flatメソッドとは

flatMapメソッドを理解する前に、まずflatメソッドについて知っておくと、スムーズに理解できます。

flatメソッドはES2019で追加されたメソッドであり、ネストされた配列をフラットにするメソッドです。以下のサンプルコードを見てみましょう。

const example1 = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

console.log(example1.flat());
// 出力: [1, 2, 3, 4, 5, 6, 7, 8, 9]

const example2 = [
  1, 2, 3,
  [4, 5, 6],
  [[7], [8], [9]],
];

console.log(example2.flat());
// 出力: [1, 2, 3, 4, 5, 6, [7], [8], [9]]

上記のサンプルコードから分かるように、flatメソッドに引数を指定しない場合、ネストされた配列を1階層だけフラット化します。引数を指定すると、以下に示すように、より深い階層のネストされた配列をフラットにすることができます。

const example3 = [1, 2, [3, 4, [5, 6]]];

console.log(example3.flat(1)); // 1段階フラット化 → [1, 2, 3, 4, [5, 6]]
console.log(example3.flat(2)); // 2段階フラット化 → [1, 2, 3, 4, 5, 6]

flat()flat(1)は同じ動作になります。

flatMapメソッドとは

flatMapメソッドはmapメソッドで要素を変換した後にflatメソッドを適用するメソッドです。そのため、array.flatMap(callback)array.map(callback).flat()は同じ動作になります。

flatMapメソッドを使うと、配列の要素を変換しつつ、ネストされた配列をフラットにすることができます。以下のサンプルコードを見てみましょう。

const array = [1, 2, 3];
const callback = (element) => [element, element * 2];

const result = array.flatMap(callback);
console.log(result);
// 出力: [1, 2, 2, 4, 3, 6]

処理の流れ

  • mapメソッドの動作で[1, 2, 3][[1, 2], [2, 4], [3, 6]]に変換
  • flatメソッドの動作で[[1, 2], [2, 4], [3, 6]][1, 2, 2, 4, 3, 6] に変換

flatメソッドとflatMapメソッドの違い

flatメソッドは単にネストされた配列をフラットにするだけの機能を持っています。一方、flatMapメソッドは配列の要素を変換しつつ、ネストされた配列をフラットにすることができます。ただし、flatMapメソッドは1階層のネストしかフラットにしません。より深くネストされた配列をフラットにする場合はflatメソッドを使用する必要があります。

flatMapメソッドの構文

flatMapメソッドの構文を以下に示します。

flatMapメソッドの構文

array.flatMap(callback);
array.flatMap(callback, thisArg);

arrayは処理対象の配列です。flatMapメソッドの引数と返り値を以下に示します。

引数

  • callback
    • 配列の各要素に対して実行されるコールバック関数です。この関数は以下の引数を取ります。
    • element
      • 配列で現在処理中の要素
    • index(省略可)
      • 現在処理中の要素のインデックス番号
    • array(省略可)
      • flatMapメソッドが呼び出された元の配列
  • thisArg(省略可)
    • callback関数内でthisとして参照する値

返り値(戻り値)

  • flatMapメソッドは、callback関数の結果を1段階フラット化した新しい配列を返します。

以下にすべての引数を使用したサンプルコードを示します。

const numbers = [1, 2, 3];

const multiplier = {
  factor: 10,
};

const callback = function (element, index, array) {
  console.log(`element: ${element}, index: ${index}, array: ${array}, this.factor: ${this.factor}`);
  return [element, element * this.factor];
};

const result = numbers.flatMap(callback, multiplier); // thisArg を渡す
console.log(result);

// 出力
// element: 1, index: 0, array: 1,2,3, this.factor: 10
// element: 2, index: 1, array: 1,2,3, this.factor: 10
// element: 3, index: 2, array: 1,2,3, this.factor: 10
// [ 1, 10, 2, 20, 3, 30 ]

thisArgとしてmultiplierオブジェクトを渡しています。callback内でthis.factorを参照しており、「各要素を元の値」と「各要素の値にthis.factorを掛けた値」を返しています。

flatMapメソッドの使い方

flatMapメソッドについて、以下に示している使い方を順番に説明します。

  • 配列の要素を増やす
  • 配列の要素を削除する
  • 文字列を分割してフラットにする
  • 配列の要素の重複を除去する

配列の要素を増やす

callback関数の戻り値に要素数が2つ以上の配列を返すと、呼び出し元の配列よりも要素数を増やすことができます。以下のサンプルコードを見てみましょう。

const array = [1, 2, 3];
const callback = (element) => [element, element];

const result = array.flatMap(callback);
console.log(result);
// 出力: [1, 1, 2, 2, 3, 3]

処理の流れ

  • mapメソッドの動作で[1, 2, 3][[1, 1], [2, 2], [3, 3]]に変換
  • flatメソッドの動作で[[1, 1], [2, 2], [3, 3]][1, 1, 2, 2, 3, 3]に変換

配列の要素を削除する

callback関数で[]を返せば、要素を削除することができます。以下のサンプルコードでは奇数の要素を削除しています。

const array = [1, 2, 3];
const callback = (element) => (element % 2 === 0 ? [element] : []);

const result = array.flatMap(callback);
console.log(result);
// 出力: [2]

処理の流れ

  • mapメソッドの動作で[1, 2, 3][[], [2], []]に変換
  • flatメソッドの動作で[[], [2], []][2]に変換

文字列を分割してフラットにする

flatMapメソッドを使用すると、配列内の文字列を単語ごとに分割し、一つの配列にまとめることができます。以下のサンプルコードを見てみましょう。

const words = ['Hello World', 'How are you?'];
const callback = (word) => word.split(' ');

const result = words.flatMap(callback);
console.log(result);
// 出力: ['Hello', 'World', 'How', 'are', 'you?']

処理の流れ

  • mapメソッドの動作で['Hello World', 'How are you?'][['Hello', 'World'], ['How', 'are', 'you?']]に変換
  • flatメソッドの動作で[['Hello', 'World'], ['How', 'are', 'you?']]['Hello', 'World', 'How', 'are', 'you?']に変換

なお、mapメソッドだけを使用すると、配列のネストがフラットになりません。

const words = ['Hello World', 'How are you?'];
const callback = (word) => word.split(' ');

const result = words.map(callback);
console.log(result);
// 出力: [['Hello', 'World'], ['How', 'are', 'you?']]

配列の要素の重複を除去する

flatMapメソッドを使用すると、配列内の重複する要素を簡単に削除できます。以下のサンプルコードを見てみましょう。

const array = [1, 2, 2, 3, 3, 3];
const callback = (element, index, selfArray) =>
  selfArray.indexOf(element) === index ? [element] : [];

const result = array.flatMap(callback);
console.log(result); 
// 出力: [1, 2, 3]

処理の流れ

  • mapメソッドの動作で[1, 2, 2, 3, 3, 3][[1], [2], [], [3], [], []]に変換
    • selfArray.indexOf(element) === indexの条件を満たす最初の出現位置の要素のみを配列に格納
    • それ以外は[]を返すことで、要素を削除している。
  • flatメソッドの動作で[[1], [2], [], [3], [], []][1, 2, 3]に変換

APIレスポンスのネストされたデータをフラット化する

flatMapメソッドを使用すると、APIレスポンスのネストされたデータをフラット化することができます。以下のサンプルコードを見てみましょう。

const apiResponses = [
  { data: [1, 2] },
  { data: [3, 4] },
  { data: [5, 6] },
];

const callback = (res) => res.data;
const result = apiResponses.flatMap(callback);
console.log(result);
// 出力: [1, 2, 3, 4, 5, 6]

処理の流れ

  • mapメソッドの動作で[ { data: [1, 2] }, { data: [3, 4] }, { data: [5, 6] } ][[1, 2], [3, 4], [5, 6]]に変換
  • flatメソッドの動作で[[1, 2], [3, 4], [5, 6]][1, 2, 3, 4, 5, 6]に変換

本記事のまとめ

この記事では『flatMapメソッド』について、以下の内容を説明しました。

  • flatメソッド
    • 配列のネストをフラットにするメソッド(ES2019で追加)
    • flat(0)flat(1)で1階層だけフラット化
    • flat(n)を指定すれば、n階層までフラット化可能
  • flatMapメソッド
    • map()で要素を変換した後にflat()を適用
    • array.flatMap(callback)array.map(callback).flat()と同じ動作
    • ネストを1階層のみフラット化する
  • flatMapとmapの違い
    • map()だけではネストがそのまま残る
    • flatMap()を使うと自動的に1階層フラット化される

お読み頂きありがとうございました。