Arrays are one of the most common data structures used in programming. To access each element in an array, sequential "for loops" may be one technique you use often—but do you know that you can use filter(), map(), and reduce() methods in JavaScript to process arrays more elegantly?
If you haven't heard about them, don't worry. This tech tutorial will show you how they can be used to process arrays efficiently without having to write sequential for loops. Should you avoid sequential for loops all the time? Are they bad? Read on to find out.
Why avoid sequential looping on an array?
The traditional code for loops are useful, powerful, and not difficult to write. However, most developers will agree that typing them can be kind of a pain! It's not bad using this technique, but it often makes your code too lengthy and hard to understand if overused.
The format of sequential for loop:
for (var i = 0; i < array.length; i++) {
// do something with array[i]
}
The pain points? You need to write a counter variable "i", which might create a global variable if you're not careful when declaring it. Besides, you need to track the length of the array explicitly. Another thing is making sure that you start with the right counter value, whether it's 0, 1, or other values. So...how can we make it more simple?
Some tips to simplify your JavaScript code
Now, let's see some tips using filter(), map(), and reduce() methods in JavaScript to avoid a sequential "for loop" when processing arrays. All of these functions process an array with a callback function and return the processed array or other data.
Tip 1: Use filter() to filter items from an array
Just like its name, the filter() method filters specific items from an array.
As an example, suppose you have the following array, which contains a list of product orders. Each element represents an "order" and has attributes such as order id, name and category of the product in the order, as well as price and tax.
var orders = [
{ id: 1, product: "White tote bag", category: "Bag", price: 300, tax: 30 },
{ id: 2, product: "Pump heels", category: "Shoes", price: 350, tax: 35 },
{ id: 3, product: "Elastic loafers", category: "Shoes", price: 100, tax: 10 },
{ id: 4, product: "Pearl necklace", category: "Accessories", price: 50, tax: 5 },
{ id: 5, product: "Yellow purse", category: "Bag", price: 200, tax: 20 }
];
Now, you only want orders that have products in the "Bag" category. You can use a "for loop" to achieve this, as follows:
var ordersContainingBag = [];
for (var i = 0; i < orders.length; i++) {
if (orders[i].category === "Bag") {
ordersContainingBag.push(orders[i])
}
}
Notice that we use a counter variable "i" and declare an empty array ordersContainingBag to store the final result.
As an alternative, you can use a forEach loop to make your code more pleasant. However, you still need to declare the empty array beforehand, as shown below:
var ordersContainingBag = [];
orders.forEach(function (order) {
if (order.category === "Bag") {
ordersContainingBag.push(order);
}
});
What about using filter()? Well, the code will look like this below:
var ordersContainingBag = orders.filter(function (order) {
return order.category === "Bag";
});
That's it! Very simple, right? The code is even shorter if you use the arrow function as follows:
var ordersContainingBag = orders.filter(order => order.category === "Bag");
So, how does the filter() function work? Basically, it iterates over each element in the array and returns a new array with only elements that match the specified criteria. It does not change the original array.
Tip 2: Use map() to transform each item in an array
The map() method lets you modify each item in an array. With this technique, it's possible to do simple numeric or string operations as well as complex ones like changing the array structure.
Let's say you want to create a new array from the orders array, but you want each element to have only these 3 attributes: id, product, and total, where the total is calculated from price + tax. Here's how the code looks like when using map():
var ordersContainingBag = orders.map(order => {
return {
id: order.id,
product: order.product.toUpperCase(),
total: order.price + order.tax
};
});
A browser's console result:
As you can see, the resulting array has the same length as the original array but has only 3 attributes. As expected, all the values for the product attribute are in uppercase, and totals show the correct results.
Tip 3: Use reduce() to replace filter().map()
Compared with the other methods, reduce() might be the most difficult to understand, especially with unclear explanations that can be found on the web. Most new developers find it confusing, but let's try to understand with a simple explanation below.
What is reduce()? It's a function that takes an array and reduces it to a single value. This single value can be anything: a number, string, object, or another array, as long as it can be stored in a single variable.
You'll probably find that this method is often used to return the sum of all the elements in an array. It's also powerful that you can use to replace other functions such as filter() and map().
Now, let's see an example.
With our previous orders array, say you want to filter orders that have products in the "Bag" category, and you want each element to have only these 3 attributes: id, product, and total. Here's the expected result:
To get the above array, you can combine filter() and map() as follow:
var ordersContainingBag = orders
.filter(order => order.category === "Bag")
.map(order => {
return {
id: order.id,
product: order.product.toUpperCase(),
total: order.price + order.tax
};
});
However, if you want, you can also use reduce() to replace .filter().map():
var ordersContainingBag = orders.reduce(function(bag, order) {
if (order.category === "Bag") {
bag.push({id: order.id,
product: order.product.toUpperCase(),
total: order.price + order.tax});
}
return bag;
}, []);
Conclusion
Using a sequential "for loop" is not bad, but writing it all the time will make your code harder to read. You can also make silly mistakes accidentally because of extra stuff like the counter variable so we hope our ways to avoid sequential loops was useful.
Try to replace some of your "for loops" code with map(), filter(), and reduce() methods where it seems to fit. By applying these techniques, your code will be easier to read and less clunky. Thanks for reading and happy coding!
Like what you've read or want more like this? Let us know! Email us here or DM us: Twitter, LinkedIn, Facebook, we'd love to hear from you.