Zum Inhalt springen

I Finally Understood map, filter And reduce In JavaScript

Intro

Understanding map(), filter(), and reduce() and how to use them is essential for a JavaScript developer. For the longest time, I was struggling with them, mainly ** reduce(). But today I said, that’s it… I will learn it today. So I did, and here is a **summary of what I’ve learned.

I tried to write it as easily as possible and include a good amount of examples.
Hope you learn something new! 😃

map(), filter() and reduce() are used to manipulate arrays. Basically, all of them are methods of the Array object in JavaScript.

const arr = [1, 2, 3];

arr.map(...);
arr.filter(...);
arr.reduce(...);

Now let’s explore them one by one. map() is the easiest out of them, but it has the most explanation. Because there are a lot of similarities between these methods and I explain the basics only once in the map() section.

map():

map() goes through all the elements in an array, does something to each element, and returns a new array. By default, the number of elements that it returns is the same as the number of elements in the original array.

So:

const arr = [1, 2, 3, 4]; // length is 4.

arr.map(item => item * 2) // returns [2, 4, 6, 8] - length is 4 too.

map() is very similar to forEach, if you are familiar with it. It takes 3 parameters (at least one is needed, the rest are optional) and a callback function. The parameters define what you can access in the callback function. The callback function defines the change that needs to happen on each of the elements.

The three parameters include item, index, and array.

  • item is the current element in the array that the map() goes through.

  • index is the index of the element in the array.

  • array is the original array.

You can name these anything you want, just notice the order is important. The first parameter you pass in (any name) is the element, the second one is the index, and the third one is the array.

const numbers = [1, 2, 3, 4];

// I named the item number here
numbers.map(number => number * 2); // multiply each number by 2

If you need to pass in multiple parameters, you need to use ().

numbers.map((number, index) => number * index); // Here I pass in both the element and the index of each item in the array, multiply them by each other and return them

This might be a bit confusing, you might ask what the hell? How does it return a new array? How can I even use the returned array? I’ll explain everything, don’t worry! 😉

What if you don’t need the element and you only need the index, or just the original array? As I said, the parameters are not based on their names but rather on their order. So you have to skip the item and index to get to the original array, if that is the only thing you want.

In a situation like this, you can use _. _ is just a common convention **among programmers for saying: „I’m not using this variable.“.
Just note some frameworks like **Lodash
use _ as a global variable, so avoid name clashes depending on the environment. In that case, you can just name them anything you want.

Here we are using _ for the element, and __ for the index. Because we only need the original array and we ignore everything else.

numbers.map((_, __, array) => ...);

In simple examples like above, map() returns the value automatically and does not need a return keyword. This is only possible if your callback function is just one line.

But if your callback function has more steps, you need to use {} and in the end use a return keyword (Much like a normal function). Here is an example:

const users = [
  { firstName: 'James', lastName: 'Miller', age: 25 },
  { firstName: 'Emily', lastName: 'Taylor', age: 30 }
];

const formattedUsers = users.map(user => {
  const fullName = `${user.firstName} ${user.lastName}`;
  const status = user.age >= 18 ? 'Adult' : 'Minor';

  return {
    fullName,
    age: user.age,
    status
  };
});

console.log(formattedUsers);

In the example above, the callback function is much more complex than just a simple multiplication. We save the returned value of the callback function, and we log it out later.

🔴 You can skip this next part!

Above, I said normally map() returns arrays that are the same length as the original array. Why do I say normally? 🤔

This is a bit out of the scope of this article, but if you used map() in React, you are returning DOM elements or other React components. With things like conditional rendering, you can render only a few of the array elements. Again, this is really not that important, just wanted to mention a use case where the length of the output array is less than the original array.

filter():

filter() removes elements that don’t meet a condition and returns a new array with only the items that pass.

filter() gets the same parameters as map(). You can use the parameters in the callback function, where you define the filter.

const numbers = [1, 2, 3, 4, 5 ,6];

numbers.filter(number => number%2 === 0); // filter out the even numbers
// 2, 4, 6

Here is an example with objects:

const users = [
    {id: 0, name: "Max", age: 30},
    {id: 1, name: "John", age: 15},
    {id: 2, name: "Julia", age: 20},
];

const adults = users.filter(user => user.age >= 18);

console.log(adults);
/*
[
  {id: 0, name: "Max", age: 30},
  {id: 2, name: "Julia", age: 20},
];
*/

reduce():

The name of reduce might be confusing, but if you understand what it’s doing, it will make more sense. 👍

reduce() processes each element and accumulates a single final result. Unlike map(), that is returns an array with the same length as the original array, and filter that returns an array of all the elements that passed the filter, reduce() returns only one value. The value can be a number, an object, or another array.

It has the same parameters as map() and filter(), with one exception. It gets an extra parameter called the accumulator. Usually, the element is called current in reduce(). So:

acc: The extra parameter that only reduce can get. acc is the final value that will be returned.

cur: The current element in the array that reduce() goes through. For some reason, people usually name it cur instead of item or element.
As said before, you can name these parameters whatever you want.

index and array: As before.

The accumulator is the value that reduce() returns finally. It’s the value that we are accumulating as we go through the array.

Here is a simple example, summing up the elements in an array:

const numbers = [1, 2, 3];

const sum = numbers.reduce((acc, cur) => acc = acc + cur);

console.log(sum);
// 6

To understand it better, let’s go through it one by one.
reduce() takes the first elements of the array (1 in this example) and updates the acc value. cur is 1, but what is the value of acc? 🤔 Good question!

Here is another unique feature of reduce()! reduce() can get another parameter after the callback function, the initValue. Meaning the starting value of the accumulator. accumulator is very important in reduce(), since it is the value that we are going to return at the end, it makes sense to have an initial value and accumulate from there. 🧠

So let’s add the initValue:

const sum = numbers.reduce((acc, cur) => acc = acc + cur, 0); // 0 is the initValue

console.log(sum);
// 6

If you run these two codes, you get the same result. That is because the initValue is 0 by default, so it does not make any difference in this example. But let’s say you want to return an object; for this, you need to set the initValue to an empty object ({}).

Let’s explore more examples since reduce() is by far the most difficult method.

Here we are using reduce() to count how many of each letter we have:

const letters = ['a', 'b', 'a', 'c', 'b', 'a'];

const counts = letters.reduce((acc, letter) => {
  acc[letter] = (acc[letter] || 0) + 1;
  return acc;
}, {});

console.log(counts);
// { a: 3, b: 2, c: 1 }

Here we are using reduce() to separate the items based on their category. We are reducing the array into one object, with the categories being the keys in the object. Also, much like before, since the operation has more than one step, we need to use {} with the return keyword at the end.

const items = [
    {name: "apple", type: "fruit"},
    {name: "carrot", type: "vegetable"},
    {name: "banana", type: "fruit"},
];

const categoryObject = items.reduce((acc, cur) => {
    acc[cur.type] = acc[cur.type] || []; // make a new key if there is not one already
    acc[cur.type].push(cur.name); 
    return acc;
}, {});

console.log(categoryObject);

// {"fruit": ["apple", "banana"], "vegetable": ["carrot"], };

Thanks for reading.

Sorry if the writing was not very good. I’m a coder, not a writer, and I didn’t use an LLM to write this article.

Any questions? Ask! 😄

Feel free to contact me on X

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert