reduce(),map(),filter()

JS

reduce()

reduce()を検索すると出てくるのが、

array.reduce(callback[, initialValue])

でもこれを読んでもいまいちピンとこない。

角カッコでいきなりカンマは省略が可能だということを表しているそう。

だからinitalValueつまり初期値を省略可能ということ。

callback関数の引数は以下の4つ

  • accumulater //前回の呼び出しの戻り値または初期値
  • currentValue//現在の要素の値
  • currentIndex//現在の要素のインデックス
  • array//reduce()が呼び出された配列

合計を求める

reduce()を使うのは合計を求めるときが多いでしょうか。

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
}, 0);
console.log(sum); // 15

これを初めて見た時に全く理解ができませんでした。

でも、reduce()メソッドは

配列の各要素に対して指定された処理を適用し、最終的に単一の値を返すために使用される

ということは、上に書いた合計は下のように出しています。

0(初期値)+1(現在の値)

1(前回の呼び出しの戻り値) + 2(現在の値)

3(前回の呼び出しの戻り値) + 3(現在の値)

6(前回の呼び出しの戻り値) + 4(現在の値)

10(前回の呼び出しの戻り値) + 5(現在の値)

で結果15になり、1+2+3+4+5=15と一致します。

平均を求める

平均を求めるときもreduce()メソッドを使えます。

const numbers = [1, 2, 3, 4, 5];

// 配列の合計を計算する
const sum = numbers.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
}, 0);

// 配列の要素数を数える
const count = numbers.length;

// 平均を計算する
const average = sum / count;

console.log(average); // 3

15÷5=3で正解ですね。

さらに、もうひとつ別のreduce()メソッドの例をあげます。

const names = ["sadako", "suzuko"];
const scores = ["40", "50"];

const combinedData = names.reduce((result, name, index) => {
  result[name] = scores[index];
  return result;
}, {});

console.log(combinedData);
↓
{ sadako: "40", suzuko: "50"}

ほう。こんな使い方もあるのですね。

これも一見callback関数の引数が違うように見えますが、同じです。

result → accumulator

name → currentValue

index→ currentIndex

となります。

こういう使い方ができるとmap()メソッドとどう違うのかと気になってきます。

map()

上と同じ例を使うと違いがよく分かります。

const mappedData = names.map((name, index) => {
  return { [name]: scores[index] };
});

console.log(mappedData);
//  [{ sadako: "40" }, { suzuko: "50" }]

まさにconsole.logで出された結果がreduce()とmap()の違いですね。

reduce()は単一の値にまとめるので、最終的には1つのオブジェクトが生成されます。

一方map()は新しい配列を生成します。

ついでにもう一つ

filter()

filter()メソッドは元の配列から条件に合致する要素のみを抽出します。

上の例でいくと、

const names = ["sadako", "suzuko", "taro"];
const scores = ["40", "50", "60"];

// スコアが50以上の生徒のみを抽出する
const filteredData = names.filter((name, index) => {
  return number(scores[index]) >= 50;
});

console.log(filteredData);
// ["suzuko", "taro"]