組み込み関数

JavaScriptのreduce()入門|配列を1つの値に集約する方法

reduce()は、配列の全要素を順番に処理し、最終的に1つの値にまとめるメソッドです。合計値の計算、オブジェクトの構築、データの集計など、幅広い用途に使えます。他の配列メソッドと比べるとやや難しいですが、使いこなせれば非常に強力なツールになります。

基本的な使い方

reduce()は2つの引数を取ります。第1引数はコールバック関数(リデューサー)、第2引数は初期値です。コールバック関数は累積値(アキュムレータ)と現在の要素を受け取り、次の累積値を返します。

JavaScript
// 基本構文
const result = array.reduce(function(accumulator, currentValue, index, array) {
  return 次の累積値;
}, 初期値);

// アロー関数を使った書き方
const result = array.reduce((acc, cur) => acc + cur, 0);

accumulator(累積値)は、前回のコールバックの戻り値です。最初の呼び出しでは初期値が使われます。初期値を省略すると配列の最初の要素が使われますが、空配列でエラーになるため、初期値を指定することを推奨します。

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

// 合計を計算
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);

// 最大値を求める
const max = numbers.reduce((acc, num) => (num > acc ? num : acc), -Infinity);
console.log(max);

// 処理の流れを確認
numbers.reduce((acc, num, index) => {
  console.log(`Step ${index}: acc=${acc}, num=${num}, result=${acc + num}`);
  return acc + num;
}, 0);
実行結果
15
5
Step 0: acc=0, num=1, result=1
Step 1: acc=1, num=2, result=3
Step 2: acc=3, num=3, result=6
Step 3: acc=6, num=4, result=10
Step 4: acc=10, num=5, result=15

データの集計とグルーピング

reduce()の真価は、配列をオブジェクトに変換する集計処理にあります。カテゴリ別の集計やグルーピングは実務で頻出するパターンです。

JavaScript
const sales = [
  { product: "りんご", category: "果物", amount: 300 },
  { product: "にんじん", category: "野菜", amount: 200 },
  { product: "バナナ", category: "果物", amount: 150 },
  { product: "キャベツ", category: "野菜", amount: 250 },
  { product: "みかん", category: "果物", amount: 400 }
];

// カテゴリ別の売上合計
const totalByCategory = sales.reduce((acc, item) => {
  acc[item.category] = (acc[item.category] || 0) + item.amount;
  return acc;
}, {});
console.log(totalByCategory);

// カテゴリ別にグルーピング
const grouped = sales.reduce((acc, item) => {
  if (!acc[item.category]) acc[item.category] = [];
  acc[item.category].push(item.product);
  return acc;
}, {});
console.log(grouped);
実行結果
{ "果物": 850, "野菜": 450 }
{ "果物": ["りんご", "バナナ", "みかん"], "野菜": ["にんじん", "キャベツ"] }

初期値に空のオブジェクト{}を渡すことで、配列からオブジェクトを構築できます。このパターンは集計レポートの作成やデータ変換で非常に便利です。

実践的な活用例

reduce()は配列のフラット化やパイプライン処理など、さまざまな場面で応用できます。

JavaScript
// 配列のフラット化(1段階)
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, arr) => [...acc, ...arr], []);
console.log(flat);

// 出現回数のカウント
const words = ["apple", "banana", "apple", "cherry", "banana", "apple"];
const count = words.reduce((acc, word) => {
  acc[word] = (acc[word] || 0) + 1;
  return acc;
}, {});
console.log(count);

// 関数のパイプライン(合成)
const pipeline = [
  (x) => x * 2,
  (x) => x + 10,
  (x) => x / 3
];
const result = pipeline.reduce((val, fn) => fn(val), 5);
console.log(result); // (5 * 2 + 10) / 3
実行結果
[1, 2, 3, 4, 5, 6]
{ apple: 3, banana: 2, cherry: 1 }
6.666666666666667
reduce()は万能だが使いすぎに注意

reduce()はほぼすべての配列操作を実装できますが、単純な処理にはmap()filter()の方が可読性が高いです。「配列を1つの値にまとめる」場面で使い、それ以外は専用メソッドを優先しましょう。

注意点

初期値を省略して空の配列にreduce()を実行するとTypeErrorが発生します。必ず第2引数に初期値を指定してください。また、アキュムレータを変更し忘れてreturnを書き忘れるとundefinedが次の累積値になるため注意が必要です。

まとめ

  • reduce()は配列の全要素を処理して1つの値にまとめるメソッド
  • 第1引数にリデューサー関数、第2引数に初期値を渡す
  • 合計・最大値・カウント・グルーピングなど幅広い集計処理に対応
  • 初期値は必ず指定する(空配列対策)
  • 単純な変換にはmap()filter()の方が適切