The reduce
function is the most complex of the standard JavaScript array functions. With reduce
,
you can compress (reduce) an array to one element.
For the reduce
function to work properly, you’ll need 2 parameters — the reducer function and the initial value.
The reducer function, unlike the functions you will use in map
and filter
, takes two parameters.
The first is the accumulator. The second is the current element of the array.
Let’s see how we can calculate the sum of all elements of an array using reduce
.
const arr = [ -1, 2, 4, 0, -5, 7 ];
const sum = arr.reduce((prev, cur) => prev + cur, 0);
console.log(sum); // 7
To make it a little clearer for you, I will rewrite this example using the for
loop.
const arr = [ -1, 2, 4, 0, -5, 7 ];
let prev = 0; // accumulator
for (let i = 0; i < arr.length; i++) {
// arr[i] is the current element of the array, same as cur in the reduce example
prev = prev + arr[i];
}
const sum = prev;
console.log(sum); // 7
— This is clearer, but it looks like there is at least one extra line.
— It’s good that you pay attention to the extra code. The assignment sum = prev
makes the for
loop example
as similar as possible to the previous one with reduce
.
— Can you elaborate on the “initial value” that we pass as the second parameter?
— When the reduce
function starts, it only has the first element of the array, so you need to add an
initial value to start the calculations. Most often, this is an empty string, null, or an empty object.
Let’s see what happens if you try to reduce
on an array of objects and don’t add an initial value.
Here’s an example of how you could calculate the total salary for the year of all employees of the company.
const employees = [
{ name: 'John Richards', salary: 155000 },
{ name: 'Lenny Mingles', salary: 75000 },
{ name: 'Travis Markham', salary: 102000 },
{ name: 'Bertha Jackson', salary: 47000 },
{ name: 'Vasya Pupkin', salary: 322000 },
];
const salariesSum = employees
.reduce((prev, cur) => prev + cur.salary);
console.log(salariesSum); // [object Object]7500010200047000322000
As a result, a weird strange string [object Object]7500010200047000322000
was displayed in the console,
due to the fact that we do not added the initial value of the accumulator.
Let’s add one console.log
to better understand what prev
is on each iteration:
const salariesSum = employees
.reduce((prev, cur) => {
console.log(prev); // added for debugging
return prev + cur.salary
});
New lines will appear in the console.
{name: 'John Richards', salary: 155000}
[object object]75000
[object object]75000102000
[object object]7500010200047000
[object object]7500010200047000322000
Here’s what happened:
- We did not specify the initial value of the accumulator and therefore the first element was used as the accumulator
the
employees
array. - By default, when trying to add an object to a number, both were converted to a string.
- On the second iteration in
prev
string[object Object]75000
which will stick together with numbers until it ends array. - Eventually we will end up with the string
[object Object]7500010200047000322000
.
— It doesn’t look like the sum of salaries of all employees.
— You are right. Does not look like it. Fortunately, fixing the problem is very easy.
Let’s add the initial value of the accumulator and make sure that the salary is calculated correctly.
const employees = [
{ name: 'John Richards', salary: 155000 },
{ name: 'Lenny Mingles', salary: 75000 },
{ name: 'Travis Markham', salary: 102000 },
{ name: 'Bertha Jackson', salary: 47000 },
{ name: 'Vasya Pupkin', salary: 322000 },
];
const salariesSum = employees
.reduce((prev, cur) => prev + cur.salary, 0);
console.log(salariesSum); // 701000
The reduce
function can be combined with map
and filter
, but it is important that reduce
is the last one
in the chain.
Let’s try to calculate the total salary of those employees who earn more than one hundred thousand.
const employees = [
{ name: 'John Richards', salary: 155000 },
{ name: 'Lenny Mingles', salary: 75000 },
{ name: 'Travis Markham', salary: 102000 },
{ name: 'Bertha Jackson', salary: 47000 },
{ name: 'Vasya Pupkin', salary: 322000 },
];
const salariesSum = employees
.filter(employee => employee.salary > 100000)
.reduce((prev, cur) => prev + cur.salary, 0);
console.log(salariesSum); // 579000
Enough theory, it’s time to move on to practice!