Sum similar keys in a JavaScript array of objects

Published December 14, 2020

Let's say we have an array of objects in JavaScript and we would like to sum the values of similar keys. What would be a simple way to do that? Let's take a look.

const kartRacers = [
  { name: 'Toad', score: 150 },
  { name: 'Mario', score: 100 },
  { name: 'Luigi', score: 50 },
  { name: 'Wario', score: 250 },
  { name: 'Mario', score: 50 },
];

Using the JavaScript reduce function

Now that we've defined our array of Mario Kart racer objects, we can use the reduce function. JavaScript's reduce function applies a reducer function that we give it, to each element of the array.

const racerScores = kartRacers.reduce((acc, { name, score }) => {
  acc[name] = acc[name] || { name, score: 0 };
  acc[name].score += score;
  return acc;  
}, {});

The first reducer function parameter is a callback function. This is the function that we want to execute on each element of the array. The first parameter of our callback function is the accumulator. The second parameter is the currentValue. It is the current element that is being processed in an iterative manner from the array.

The second reducer function parameter is the initialValue. It is the value that we want to use as the accumulator for the first call of the callback function. If we supply no initialValue, the first element in the array will be used as the initial accumulator value and currentValue will skip it.

We will use the initialValue of the reduce function to set our accumulator to an empty object.

acc[name] = (acc[name]  || { name, score: 0 });

With the first line of the callback function, we will accumulate elements by the name key.

For the first iteration of the callback function, acc[name] will be set to { name, score: 0 }.

acc[name] = { name: 'Toad', score: 0 };

The same will happen for iterations two through four because the left side of the logical OR clause || will be undefined. Thus, the right side will be used.

For the fifth iteration of the callback function, acc[name] will be set to acc[name] because we have already iterated over an element with the name 'Mario'.

acc[name] = { name: 'Mario', score: 100 };

With the second line of the callback function, acc[name].score += score, we will sum the score of a name that we already iterated over with the currentValue of a new element with the same name.

The reduce function that executes our callback function will give us the following object structure containing a sum of Mario's scores. Mario's score is now 100 + 50.

{
  Toad: {
    name: "Toad",
    score: 150
  },
  Mario: {
    name: "Mario",
    score: 150
  },
  Luigi: {
    name: "Luigi",
    score: 50
  },
  Wario: {
    name: "Wario",
    score: 250
  }
}

The result

We can then use Object.values to extract only the value portion from the nested objects.

const result = Object.values(racerScores);

The result can be seen below. This gives us the original structure we started with, but with one Mario entry containing the sum of both scores present in the original array of objects.

[
  { name: 'Toad', score: 150 },
  { name: 'Mario', score: 150 },
  { name: 'Luigi', score: 50 },
  { name: 'Wario', score: 250 },
];