Codementor Events

Wrap your head around Javascript's Reduce Method

Published May 05, 2022Last updated Oct 31, 2022
Wrap your head around Javascript's Reduce Method

Hi all at Codementor!
I want to try and explain one of the most powerful array methods in Javascript, the reduce method. I was confused by it and honestly shied away from using it until one day it just clicked, and through that click I have gained immense power.

Basic Syntax

The reduce method has two arguments:

  1. A callback function that accepts four arguments (the third and fourth are rarely used):
    1. The accumulating value of the method (we will discuss this),
    2. The current element of the array through which we're iterating,
    3. The index of the current array element,
    4. The entire array
  2. The initial value of choice

The purpose of the reduce method is to take an array and perform logic on each element to manipulate some starting value to a final result. Essentially we are reducing, or squashing down, the array to a final, crystallized result. Think of an accordion in this regard.
photo-1513696447688-c301fedbda2c

Here's how it looks in action (with some helpful Typescript):

const to10: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const sumTo10: number = to10.reduce(
  (accumulatedValue: number, currentValue: number) => {
    return accumulatedValue + currentValue;
  },
  0,
);

console.log(sumTo10); // 55

What's happening here? We are iterating through the array. In each iteration, we take the accumulating value (which starts at 0) and add the current value to it. We return this new value to be the accumulating value for the next iteration, until we finish the array. The final return statement will return our value and store it in the variable sumTo10, which is a number, matching the type of the accumulated value.

A Little Slower

  1. Our array's first value is 1. The accumulating value is 0 (the initial value set). We return 0 + 1 = 1.
  2. Our array's second value is 2. The accumulating value is 1 (from the previous iteration). We return 1 + 2 = 3.
  3. Our array's third value is 3. The accumulating value is 3 (from the previous iteration). We return 3 + 3 = 6.
  4. And so on until the last value of 10, where the accumulating value would be 45. We return 45 + 10 = 55.
  5. Because that was the last element of the array, this final value is the value returned from the reduce method and stored in the sumTo10 variable.

An Advanced Case

We can create a generic function that sums all numbers up to a certain number:

const sumNumbersUpTo = (upTo: number): number => {
  return Array(upTo)
    .fill('')
    .reduce((acc: number, _: any, index: number) => acc + index + 1, 0);
};

console.log(sumNumbersUpTo(20)); // 210
console.log(sumNumbersUpTo(100)); // 5050

Here, the function expects a number, and creates an array of that many elements, filled arbitrarily and then reduced using the same logic (Adding 1 to the index because the index begins at 0). I have used a simple arrow function return syntax instead of saying return in the reduce method here.

An Actual Use Case

Let's say we have an array of users from a database with values id and name.
We also have an array of posts with values id, userId, and title, On our frontend display we want to show a table of post titles along with the user's name, however the username is not saved on the post object. What we could do is map the posts array and return like this:

const users = [
  { id: 1, name: 'Sean' },
  { id: 2, name: 'James' },
  { id: 3, name: 'Gwen' },
];

const posts = [
  { id: 1, userId: 1, title: 'Farming Mushrooms' },
  { id: 2, userId: 1, title: 'Skipping Stones' },
  { id: 3, userId: 2, title: 'Untold Stories' },
  { id: 4, userId: 2, title: 'The Secret of Life' },
  { id: 5, userId: 3, title: 'My Undertale Speedrun World Record' },
];

const shapedPostData = posts.map((post) => ({
  ...post,
  username: users.find((user) => user.id === post.userId)?.name,
}));

which returns


  {
    "id": 1,
    "userId": 1,
    "title": "Farming Mushrooms",
    "username": "Sean"
  },
  {
    "id": 2,
    "userId": 1,
    "title": "Skipping Stones",
    "username": "Sean"
  },
  {
    "id": 3,
    "userId": 2,
    "title": "Untold Stories",
    "username": "James"
  },
  {
    "id": 4,
    "userId": 2,
    "title": "The Secret of Life",
    "username": "James"
  },
  {
    "id": 5,
    "userId": 3,
    "title": "My Undertale Speedrun World Record",
    "username": "Gwen"
  }
]

Which is all well and good, but what happens when there are 100 000 users and 1 000 000 posts? For each post, you will be performing an expensive find function on a large array.How do we make this cheaper?

Reduce The Users!

What do you mean? Well, we can use the nifty reduce method to transform the users array into a giant object of key-value pairs, which is considerably less expensive to find the desired value. Let's see how we do it:

const userNameObject = users.reduce(
  (acc: any, user) => ({ ...acc, [user.id]: user.name }),
  {},
);

Here, at each iteration, i am spreading whatever is already in the accumulated value (initialised as an empty object {}), into a new object, and adding a new key each time, which is the user's id, mapping to the user's name. This returns.

{
  "1": "Sean",
  "2": "James",
  "3": "Gwen"
}

I can then use this as a reference object when shaping the post data:

const betterShapedPostData = posts.map((post) => ({
  ...post,
  username: userNameObject[post.userId],
}));

Summary

We have learned about the powerful reduce method in javascript and how it can be used in a real-world scenario to search for data from different arrays in a less expensive manner. I hope you enjoyed the read!

Looking forward to more and more learning
~ Sean

Discover and read more posts from Sean Hurwitz
get started
post comments2Replies
Shashank Banerjea
3 years ago

I like the way, you have taken the effort to show the practical code example and why would it be beneficial.

Sean Hurwitz
3 years ago

Thanks Shashank! I appreciate the feedback!