Reduce provides a clean mechanism to compute a single value from an array, i.e. to reduce the array to a single value.
Very generally, the form is:
result = arr.reduce(callbackFunction)
The idea is to move over each array element and invoke the callback function.
We need to give the callback two arguments to provide a mechanism of reduction for the array elements. We call these accumulator (acc) and element (elem).
The simplest useful reduce example is summing the array:
const arr = [1, 2, 3, 4, 5]
const sum = arr.reduce((acc, elem) => acc + elem)
console.log(sum)
This outputs:
15
Image a sliding window in which acc stores a value accumulated in any way, and elem points to the 2nd, 3rd, 4th, etc element. The accumulator is updated and passed to the next iteration.
For demonstration, to see how reduce moves through the array:
const arr = [1, 2, 3, 4, 5]
arr.reduce((acc, elem) => {
console.log(acc);
console.log(elem);
})
This outputs:
1 // default first value of acc
2 // second element
undefined // acc is not being updated
3 // third element
undefined
4 // fourth element
undefined
5 // fifth element
Note that acc starts at the first element of the array by default.
We usually have to update acc to make reduce useful.
Reduce Starting from an Initial Value
The starting value of acc in reduce can be changed with an extra parameter. Generally:
const result = arr.reduce(callback, initialValue)
An example of an offset sum:
const arr = [1, 2, 3, 4, 5]
const result = arr.reduce((acc, elem) => {
return acc + elem
}, 10) // *start the accumulator at 10 instead of 1*
console.log(result)
This outputs:
25
That is, 10 + (1+2+3+4+5)
Calling Reduce on an Array With a Single Element
Note that when we call reduce with a single element array without an initial value for acc, the acc value is undefined.
The callback will not be called; the only option reduce has in this case is to return the elem value.
const arr = [5]
const output = arr.reduce((acc, elem) => {
console.log("Callback called") // will not print
return acc + elem
})
console.log(output)
This will return 5, without calling the callback function.
However, if we add the initial value for acc, the callback will be called.
const arr = [5]
const output = arr.reduce((acc, obj) => {
console.log("Callback called") // will print
return acc + obj
}, 0) // initial value
console.log(output)
Using Reduce with an Object as Accumulator
We can also reduce an array to an object instead of a single scalar value.
This simple example reduces the array to an object with characters as keys, and a boolean true indicating that they appear inside the array.
const arr = ['a', 'c', 'b', 'a', 'c', 'e']
const result = arr.reduce((acc, elem) => {
acc[elem] = true // build up acc
return acc // send the partially built up acc into the next iteration
}, {} ) // initial value of acc is an empty object
console.log(result)
This will return:
{
a: true,
c: true,
b: true,
e: true
}
So we have reduced the array to a single object.
Using Reduce to Accumulate an Array
We can also use reduce to build up a list of values.
This example accumulates an array of names only from an array of objects with names and values.
const arr = [
{name: 'A', val: 1},
{name: 'B', val: 2},
{name: 'C', val: 3}
]
const result = arr.reduce((acc, elem) => {
acc.push(elem.name) // accumulate an array by pushing elements
return acc
}, [] ) // acc is initially an empty array
console.log(result)
This returns:
[ 'A', 'B', 'C' ]
Index and Entire Array Parameters for Reduce
There are two more parameters available for reduce which can come in handy: the index of the current element and the entire array being reduced.
const arr = [1, 2, 3, 4, 5]
const sum = arr.reduce((acc, elem, index, wholeArray) => {
console.log(`Index: ${index}`)
console.log(`Whole array: ${wholeArray}`)
return acc + elem
}, 0) // starting value of acc
console.log(`Sum: ${sum}`)
This returns:
Index: 0
Whole array: 1,2,3,4,5
Index: 1
Whole array: 1,2,3,4,5
Index: 2
Whole array: 1,2,3,4,5
Index: 3
Whole array: 1,2,3,4,5
Index: 4
Whole array: 1,2,3,4,5
Sum: 15