NU:LOGiC Logo

【JavaScript】reduce()で配列の要素を集約! 初心者向けステップバイステップガイド

【JavaScript】reduce()で配列の要素を集約! 初心者向けステップバイステップガイド

「reduce()」メソッドは、JavaScriptで配列の要素を効率的に集約し、単一の値を得るための便利な道具です。この記事では、基本的な使い方から具体的な使用例、さらに「map()」との違いや注意点までを解説します。reduce()を理解し、上手に活用することで、コードの効率性と可読性を向上させましょう。

3行で要約すると

  • reduce()は配列の各要素を左から右に処理して、単一の出力値を生成します。
  • 使い方やパターンを知ることで、配列操作の幅がグッと広がります。
  • 正しく使用するための注意点や類似メソッドとの違いも理解しましょう。

「reduce()」の基本的な使い方

「reduce()」とは?

reduce()は、配列の各要素に対して関数を左から右に適用し、その結果を単一の値に累積していくメソッドです。以下のコードは、配列の要素を全て足し合わせる基本的な例です。

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

reduce()のコールバック関数について

reduce()メソッドにはコールバック関数が必要です。このコールバック関数は4つの引数を受け取ることができます。

  1. accumulator: 累積される値。初回の呼び出し時には、reduce()の第二引数として渡された初期値(あるいは配列の初めの要素)がここに入ります。
  2. currentValue: 現在処理中の配列の要素。
  3. currentIndex: 現在処理中の要素のインデックス。初期値が提供されなければ、0から開始します。
  4. array: reduce()が呼び出された元の配列。

以下のコードは、これらの引数を利用して配列の要素を全て足し合わせる基本的な例です。

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((accumulator, currentValue, currentIndex, array) => {
    console.log(`累積値: ${accumulator}, 現在の値: ${currentValue}, インデックス: ${currentIndex}`);
    return accumulator + currentValue;
}, 0);

// 出力結果:
// 累積値: 0, 現在の値: 1, インデックス: 0
// 累積値: 1, 現在の値: 2, インデックス: 1
// 累積値: 3, 現在の値: 3, インデックス: 2
// 累積値: 6, 現在の値: 4, インデックス: 3

console.log(sum); // 10

この例では、reduce()の各ステップでのaccumulatorcurrentValueの値がどう変わるのか、そしてcurrentIndexがどのように進行するのかを確認することができます。

「reduce()」の使用例4パターン

配列の合計

先程の例と同じですが、reduce()を使用して配列の数値を合計するのは最も一般的な使い方です。

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, val) => acc + val, 0);
console.log(sum); // 10

配列内のオブジェクトをキーで集約

オブジェクトの配列をキーによって集約する際にも利用します。

const fruits = [
    { name: 'apple', count: 2 },
    { name: 'banana', count: 3 },
    { name: 'apple', count: 1 }
];
const fruitCounts = fruits.reduce((acc, fruit) => {
    acc[fruit.name] = (acc[fruit.name] || 0) + fruit.count;
    return acc;
}, {});
console.log(fruitCounts); // { apple: 3, banana: 3 }

配列をフラット化

reduce()メソッドを使用すると、多次元の配列を単一の配列にフラット化することができます。この時、コールバック関数は現在の累積値(accumulator)を配列として、現在の要素(currentValue)をその累積値の配列に結合する形で追加していきます。

以下のコードは、この方法を使用して配列をフラット化しています。

const nestedArrays = [[1, 2], [3, 4], [5, 6]];
const flatArray = nestedArrays.reduce((accumulator, currentValue) => {
    console.log(`累積値: ${accumulator}, 現在の値: ${currentValue}`);
    return accumulator.concat(currentValue);
}, []);

// 出力結果:
// 累積値: [], 現在の値: [1, 2]
// 累積値: [1, 2], 現在の値: [3, 4]
// 累積値: [1, 2, 3, 4], 現在の値: [5, 6]

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

この例で、コールバック関数がreduce()の各ステップでどのように動作するか確認できます。具体的には、accumulator(現在までのフラット化された配列)に、currentValue(現在の要素となる配列)を連結する形で追加しています。その結果、多次元配列が単一のフラットな配列に変換されます。

最大値の取得

reduce()を使用して配列の中の最大値を取得することもできます。このときのコールバック関数は、現在の累積値(accumulator)と配列の現在の要素(currentValue)を比較し、大きい方の値を次のステップの累積値として返します。

以下のコードでは、この方法を使用して配列の中の最大値を取得しています。

const numbers = [10, 58, 2, 39, 16];
const max = numbers.reduce((accumulator, currentValue) => {
    console.log(`累積値: ${accumulator}, 現在の値: ${currentValue}`);
    return accumulator > currentValue ? accumulator : currentValue;
});

// 出力結果:
// 累積値: 10, 現在の値: 58
// 累積値: 58, 現在の値: 2
// 累積値: 58, 現在の値: 39
// 累積値: 58, 現在の値: 16

console.log(max); // 58

この例では、コールバック関数がreduce()の各ステップでどのように動作するかが分かります。具体的には、accumulatorcurrentValueの2つの値を比較し、大きい方の値を次のステップへと持ち越しています。その結果、配列の中で最も大きな値がaccumulatorとして最後まで保持され、最終的にその値がmaxとして取得されます。

「reduce()」と「map()」

「map()」とは?

map()は配列の各要素に関数を適用して、その結果を新しい配列として返すメソッドです。

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8]

「reduce()」と「map()」の違い

reduce()map()はJavaScriptの配列のメソッドとしてよく利用されますが、それぞれ異なる動作と目的を持っています。

reduce()は配列の各要素を左から右へ処理し、単一の出力値を生成するためのメソッドです。例として、配列内の数値の合計を取る場合を考えましょう。

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

一方、map()は配列の各要素に関数を適用し、その結果から新しい配列を生成します。元の配列は変更されません。例として、配列の各要素を2倍にした新しい配列を生成する場合を考えましょう。

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8]

要点としては、reduce()は配列全体を単一の値に「集約」するのに対して、map()は各要素に処理を適用して新しい配列を作成することです。これらの違いを理解しておくことで、どのメソッドをいつ使用するべきかの判断が容易になります。

「reduce()」を使用する際の注意点

初期値を設定すること

reduce()メソッドを使用する際、初期値を設定しないとエラーが発生する可能性があります。特に、配列の要素数が0の場合、初期値が設定されていないとreduce()は動作せず、TypeErrorがスローされます。

const emptyArray = [];
try {
  const result = emptyArray.reduce((acc, cur) => acc + cur);
} catch (error) {
  console.error(error.message);  // "Reduce of empty array with no initial value"
}

上記のコードでは、空の配列に対してreduce()を呼び出していますが、初期値を提供していないため、エラーメッセージ "Reduce of empty array with no initial value" が出力されます。

また、配列が1つの要素だけを持つ場合、初期値を設定しないと、その1つの要素が累積値として自動的に選ばれます。これが意図した動作でない場合、意図しない結果が返されることがあります。

初期値を設定することで、エラーを防ぐだけでなく、reduce()の動作をより明確にすることができます。

「reduce()」の使い方まとめ

reduce()は非常に多機能なメソッドですが、基本の使い方や注意点を押さえれば、配列操作の幅が広がります。日常のコーディングに積極的に取り入れ、その力を最大限に引き出しましょう。