logo

reduce()って、いつ使うんだろう

2023-07-21
2 years ago

開発環境

  • typescript 5.1.6

本題

日々の業務の中でソースコードを眺めていると、map(), filter(), some(), find()など配列操作をよく行っていますが、reduce()が全くないことに気づきました。

そもそも、いつ使うんだろう?というところで、活用例を紹介します。

reduce()とは

JavaScriptにおけるreduce()は、高階関数の一つであり、配列を単一の値にまとめるために使用されます。配列の要素を順番に処理し、各要素に対して指定したコールバック関数を実行します。このコールバック関数は、蓄積値(accumulator)と現在の要素(current value)を引数として受け取り、新たな蓄積値を返すことが期待されます。

reduce()は以下のような構文を持ちます

array.reduce(callback, initialValue)
  • array: 処理対象の配列
  • callback: 配列の各要素に対して実行するコールバック関数
  • initialValue: 蓄積値の初期値(省略可能)

他にも省略可能な引数はありますが、あまり使用する頻度が高くなさそうなので割愛します。


reduce()の動作は、配列内の要素を左から順に処理し、最終的な結果を返します。初期値を指定することで、空の配列や要素が1つしかない場合にも正しい結果を得ることができます。

reduce()は数値の集計や要素の結合、フィルタリング、グループ化など、多くのシーンで役立つ便利なメソッドです。柔軟な処理が可能なため、JavaScriptで複雑な配列操作を行う際に重宝します。

活用例

  • 配列内の数値の合計を計算する例
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, current) => acc + current, 0);

console.log(sum);
// Output: 15
  • 配列内の数値の最大値を求める例
const numbers = [12, 3, 8, 25, 6];
const max = numbers.reduce((acc, current) => (current > acc ? current : acc), numbers[0]);

console.log(max);
// Output: 25
  • 配列内のオブジェクトの特定プロパティを集計する例
const data = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Eve', age: 28 },
];
const totalAges = data.reduce((acc, current) => acc + current.age, 0);

console.log(totalAges);
// Output: 83
  • 配列内の文字列要素を結合してURLパスを生成する例
const urlParts = ['https://example.com', 'api', 'users', '123']

const fullPath = urlParts.reduce((acc, current) => {
  return `${acc}/${current}`
}, '')

console.log(fullPath)
// Output: 'https://example.com/api/users/123'
  • 条件に基づいた要素のフィルタリングをする例
const numbers = [1, 2, 3, 4, 5];

const evenNumbers = numbers.reduce((acc, current) => {
  if (current % 2 === 0) {
    return [...acc, current];
  }
  return acc;
}, []);

console.log(evenNumbers);
// Output: [2, 4]
  • .map().filter()をreduce()で置き換える例
const products = [
  { id: 1, category: 'fruit', name: 'apple' },
  { id: 2, category: 'fruit', name: 'orange' },
  { id: 3, category: 'vegetable', name: 'carrot' },
  { id: 4, category: 'fruit', name: 'banana' },
];

// .map().filter()
const targetNames = products
  .map((product) => product.category === 'fruit' && product.name)
  .filter(Boolean)

// reduce()
const targetNames = products.reduce(
  (acc, current) => (current.category === 'fruit' ? [...acc, current.name] : acc),
  [],
)

console.log(targetNames)
// Output: ["apple", "orange", "banana"]

さいごに

元も子もないですが、reduce()じゃないとダメ、と思うようなケースはない(はず)です。

  • 条件に基づいた要素のフィルタリングをする例

は素直にfilter()を利用した方が分かりやすいです。

一方で処理した結果を累積するという点では他にない良さかなと思います。


既存の実装を紹介した活用例に近い形で書き換えるとコードがスッキリするかな?、読みやすくなるかな?というきっかけになると嬉しいです。

参照