JavaScriptのreduceの使い方: 配列を走査し値を蓄積する
- 作成日: 2020-08-15
- 更新日: 2023-12-28
- カテゴリ: JavaScript
JavaScriptのreduceの使い方
JavaScriptの配列にはreduce
メソッドがあります。
これの使い方を解説します。
reduce()
を使うと配列を走査することができます。
またreduce()
はmap()
やfilter()
などと比べると少し特殊なメソッドです。
↓はreduce
のサンプルコードです。
const arr = [1, 2, 3]
const result = arr.reduce((acc, cur) => acc + cur)
console.log(result)
// 6
関連記事
reduceの動作
reduce
は最初はわかりづらいですが、原理がわかれば簡単です。
reduce
は第1引数に関数を渡せます。
この関数の第1引数には「蓄積された値」、第2引数には「現在の要素」が渡されます。
「蓄積された値」は関数の戻り値のことです。
たとえば[1, 2, 3]
という配列のreduce
を呼び出したとします。
そうするとreduce
は配列の先頭の要素から順に辿っていきます。
const arr = [1, 2, 3]
const result = arr.reduce((acc, cur) => acc + cur)
console.log(result)
// 6
acc
(accumulator)には初期値として配列の先頭の要素が渡されます。
そしてcur
(current value)にはその次の要素が渡されます。
関数の戻り値は次の走査でacc
になります。
↓の動作を見てみてください。
const arr = [1, 2, 3, 4]
const result = arr.reduce((acc, cur) => {
console.log(`acc: ${acc}, cur: ${cur}`)
return acc + cur
})
console.log(result)
出力結果↓。
acc: 1, cur: 2
acc: 3, cur: 3
acc: 6, cur: 4
10
[1, 2, 3, 4]
という配列がreduce()
で走査されます。
acc
には蓄積されていく値が渡され、cur
には現在の配列の要素が渡されます。
acc
は配列の1番目の要素の値から始まり、cur
は配列の2番目の要素から渡されます。
このようにreduce()
はちょっと使い方が独特です。
🦝 < 面食らうよね
🐭 < 変わったメソッドだぁ
Accumulatorって?
acc
は何なのかというとAccumulator
(アキュムレーター)の略です。
Accumulator
は和訳すると
蓄積者、蓄財家、蓄電池、累算器
のような意味を持ちます。
つまり計算の結果を溜めていく蓄財家ということですね。
reduce
では関数のacc
という引数に走査した結果の値が蓄積されていきます。
このacc
に加算される値は関数の返り値になります。
reduceのコールバック関数
reduce
の第1引数に渡せるのはアロー関数か普通の関数です。
const arr = [1, 2, 3]
const result = arr.reduce((acc, cur) => {
return acc + cur
})
↑の場合はアロー関数になります。
const arr = [1, 2, 3]
const result = arr.reduce(function (acc, cur) {
return acc + cur
})
↑の場合は普通の関数です。
アロー関数と普通の関数を使った場合の違いはthis
の参照先が異なる点です。
アロー関数はthis
は関数の外になりますが、普通の関数はthis
は関数の中になります。
reduceのコールバック関数の引数
reduce
に渡す関数の引数は↓のようになっています。
- 第1引数: 蓄積された値
- 第2引数: 現在の要素
- 第3引数: 現在の添え字
- 第4引数: 走査中の配列
これらは簡単なコードで確認することが出来ます。
const arr = [1, 2, 3, 4]
const result = arr.reduce((acc, cur, index, me) => {
console.log(`acc: ${acc}, cur: ${cur}, index: ${index}, me: ${me}`)
return acc + cur
})
↑のコードの結果↓。
acc: 1, cur: 2, index: 1, me: 1,2,3,4
acc: 3, cur: 3, index: 2, me: 1,2,3,4
acc: 6, cur: 4, index: 3, me: 1,2,3,4
添え字が1
から始まってる点に注意してください。
つまり配列の要素(cur
の値)は添え字1から(2番目から)始まります。
添え字0
の要素はreduce
の初期値(acc
の値)として使われています。
me
には走査中の配列が渡されます。
つまり↑の場合はarr
とme
は同じものになります。
reduceの初期値
reduce
には初期値を明示的に渡せます。
reduce
の第2引数に初期値を渡すと、reduce
はその初期値から走査を開始します。
const arr = [1, 2, 3, 4]
const result = arr.reduce((acc, cur) => {
console.log(`acc: ${acc}, cur: ${cur}`)
return acc + cur
}, 10)
console.log(result)
// 20
acc: 10, cur: 1
acc: 11, cur: 2
acc: 13, cur: 3
acc: 16, cur: 4
20
↑の場合、走査する配列は[1, 2, 3, 4]
で合計は10
ですが、初期値が10
になっているので計算の結果は20
になります。
10
が10 + 1
で11
に、そして11
が11 + 2
で13
に、という感じでacc
が更新されていきます。
reduceの使用例
reduce
の使用例を紹介します。
配列の合計値を得る
すでに何度も紹介してますが、配列の合計値を得るには↓のようにします。
const arr = [1, 2, 3, 4]
const result = arr.reduce((acc, cur) => acc + cur)
console.log(result)
// 10
reduce
を使わずに普通のfor文を使った場合は↓のようなコードになります。
const arr = [1, 2, 3, 4]
let result = 0
for (const el of arr) {
result += el
}
console.log(result)
// 10
またmap()
を使う方法もあります。
map()
を使った場合は↓のようなコードになります。
const arr = [1, 2, 3, 4]
let result = 0
arr.map(el => {
result += el
})
console.log(result)
// 10
関連記事
JavaScriptのmapの使い方: 配列に一括処理をして新しい配列を作成する
map()
は本来は配列から別の配列を生成するメソッドです。
しかし↑のように配列を走査したいような処理にも使うことができます。
効率的には普通のfor文を使った方がいいかもしれません。
理由はmap()
は新しい配列を生成するからです。
しかし計測はしてないので実際はどうかはわかりません。
要素の出現回数を数える
配列の要素の出現数を数えて、それらを保存したオブジェクトを返すサンプルです。
統計に使えそうですね。
const arr = ['Cat', 'Dog', 'Bird', 'Cat']
const result = arr.reduce((acc, key) => {
if (key in acc) {
acc[key]++
} else {
acc[key] = 1
}
return acc
}, {})
console.log(result)
// { Cat: 2, Dog: 1, Bird: 1 }
参考: Array.prototype.reduce() - JavaScript | MDN
reduce
を使わない場合は↓のようなコードになります。
const arr = ['Cat', 'Dog', 'Bird', 'Cat']
let result = {}
for (const key of arr) {
if (key in result) {
result[key]++
} else {
result[key] = 1
}
}
console.log(result)
// { Cat: 2, Dog: 1, Bird: 1 }
心なしかreduce()
を使った方が処理が複雑に見えますね。
このケースでは普通のfor文を使った方が良いかもしれません。
2次元配列を1次元配列にする
2次元配列を1次元にして平らにするサンプルです。
const arr = [[1, 2], [3, 4]]
const result = arr.reduce((acc, el) => {
return acc.concat(el)
}, [])
console.log(result)
// [ 1, 2, 3, 4 ]
参考: Array.prototype.reduce() - JavaScript | MDN
reduce
を使わない場合は↓のようなコードになります。
const arr = [[1, 2], [3, 4]]
let result = []
for (const el of arr) {
result = result.concat(el)
}
console.log(result)
// [ 1, 2, 3, 4 ]
このケースではreduce()
が効率的に使われてるように見えます。
acc.concat(el)
の返り値を有効利用しているのでおもしろいですよね。
問題
Q1: reduce
の走査で、最初に関数が呼ばれる時のacc
の値として適当なものを答えよ
- 配列の1番目(0オリジン)の要素
- 配列の0番目(0オリジン)の要素
- reduceの第2引数
Q2: reduce
に渡すコールバック関数の第4引数として適当なものを答えよ
- 蓄積された値
- 添え字
- 走査中の配列
答え
Q1: 2, 3
Q2: 3