Reduce is a Javascript method which has been around for a while, but we still sometimes forget the potential this method has to offer, in this post I will go further the classic example we have all seem.

const data = [15, 3, 20];
const initialValue = 0;

const sum = data.reduce((accumulator,value) => accumulator + value, initialValue);

console.log(sum) // 38

Concept

Reduce is a callback method which can take four arguments, the accumulator, the previous value, the array index and the array itself ( most of the time is used just with the first two). The first time it runs, the accumulator will always be the first argument to come back which is equal to the initial value, you can set this argument to anything, an object, array, number, etc, like we see in the previous example const initialValue = 0;. The second time it runs, it will return the same accumulator plus whatever we decide to do with it.

Let's do a voting system

Let’s break it down into small steps, we have an array of cities, we want to know how many votes each one got.

const cities = [
  "Paris",
  "Paris",
  "London",
  "London",
  "London",
  "Paris",
  "Amsterdam",
  "London",
  "Rome"
];

let initialValue = {};

const reducer = (vote,city) => { console.log(initialValue) }

const result = cities.reduce(reducer,initialValue); 
// {} {} {} {} {} {} {} {} {}

See how we can call an almost empty function with reduce by just passing the initial value ( { } ) and nothing weird will happend. The object runs nine times which is the number of cities we have.

Let's log the votes.

.....

const reducer = (vote,city) => { console.log(vote) }

const result = cities.reduce(reducer,initialValue); 
// {} undefined undefined undefined undefined undefined undefined undefined undefined 

As we mentioned before, the first thing reduce throws is equal to the initial value, however the second time it runs, we are not telling to do anything, that is why it throws undefined.

Let's add the full logic to it

.....

const reducer = (vote, city) => {
  vote[city]? vote[city] = vote[city] + 1 :  vote[city] = 1;
  console.log(vote)
  return vote;
}

const result = cities.reduce(reducer,initialValue);

// 
{ Paris: 1 }
{ Paris: 2 }
{ Paris: 2, London: 1 }
{ Paris: 2, London: 2 }
{ Paris: 2, London: 3 }
{ Paris: 3, London: 3 }
{ Paris: 3, London: 3, Amsterdam: 1 }
{ Paris: 3, London: 4, Amsterdam: 1 }
{ Paris: 3, London: 4, Amsterdam: 1, Rome: 1 }

We can see the break down of the nine times the function runs, if the city already exists, it will add one more vote, otherwise, it will set the value to 1. The first time it runs finds Paris and set her to one, the second time finds Paris again, adding one more vote, the same thing is applying to the other cities of course.

Using the index and array arguments

Let's make a new object where the keys are set to string and the values to numbers.

const data = ['first', 1, 'second', 2 ];

function reducer(accumulator, value, index, array) {
  if(typeof value === 'string') {
    accumulator[value] = array[index + 1]
  }
  console.log(accumulator)
  return accumulator;
}

const result = data.reduce(reducer, {});

result;
// { first: 1, second: 2 }
// { first: 1, second: 2 }

Combining reduce with other methods

They are off course more complex scenarios where you might require to loop inside an array several times and work out some logic. Let's take a bigger array with objects and create a new one with strings data that only starts with the letter a.

const teams = [
  {
    year: "2016",
    players: [
      "Aaron",
      "Michael",
      "Andres",
      "Gary",
      "Morgan"
    ]
  },
  {
    year: "2017",
    players: [
      "Alan",
      "Tom Hardy",
      "Anna",
      "Joseph",
      "Anne",
    ]
  }
];

const names = teams.reduce((acc,value) => {
  value.players.forEach(x => 
    x.toLowerCase().charAt(0) === 'a' && acc.push(x)
  )
  console.log(acc)
  return acc
},[]);

names
// [ 'Aaron', 'Andres', 'Alan', 'Anna', 'Anne' ]

As you can see, we can be creative when using reduce and take advantage of his power in different ways.