JavaScript Map, Filter, and Reduce
In functional programming, we often want to transform, select, or combine elements in a collection without modifying the original data. JavaScript provides three powerful array methods for these operations: map()
, filter()
, and reduce()
. These methods help you write cleaner, more concise, and more readable code.
Introduction
The map()
, filter()
, and reduce()
methods are higher-order functions that operate on arrays. They accept callback functions as arguments and apply these functions to each element in the array. These methods follow functional programming principles:
- They don't mutate the original array
- They return new values based on the original data
- They rely on functions as first-class citizens
Let's explore each one in detail.
The Map Method
The map()
method creates a new array by applying a function to each element in an existing array.
Syntax
const newArray = array.map(callback(currentValue[, index[, array]]) {
// return element for newArray
});
Basic Example
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(number => number * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] (original array unchanged)
Step-by-step Explanation
- The
map()
method iterates through each element of thenumbers
array - For each element, it calls the arrow function
number => number * 2
- Each result is added to a new array
- Once all elements are processed, the new array is returned
Practical Example: Formatting Data
const users = [
{ id: 1, name: 'John Doe', email: '[email protected]' },
{ id: 2, name: 'Jane Smith', email: '[email protected]' },
{ id: 3, name: 'Bob Johnson', email: '[email protected]' }
];
const usernames = users.map(user => user.name);
console.log(usernames); // ['John Doe', 'Jane Smith', 'Bob Johnson']
// Creating user display information
const userDisplayInfo = users.map(user => ({
displayName: user.name,
emailLink: `<a href="mailto:${user.email}">${user.email}</a>`
}));
console.log(userDisplayInfo);
/* Output:
[
{
displayName: 'John Doe',
emailLink: '<a href="mailto:[email protected]">[email protected]</a>'
},
{
displayName: 'Jane Smith',
emailLink: '<a href="mailto:[email protected]">[email protected]</a>'
},
{
displayName: 'Bob Johnson',
emailLink: '<a href="mailto:[email protected]">[email protected]</a>'
}
]
*/
The Filter Method
The filter()
method creates a new array containing only elements that pass a specified test.
Syntax
const newArray = array.filter(callback(currentValue[, index[, array]]) {
// return true to keep element, false to filter it out
});
Basic Example
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (original array unchanged)
Step-by-step Explanation
- The
filter()
method iterates through each element of thenumbers
array - For each element, it calls the arrow function
number => number % 2 === 0
- If the function returns
true
, the element is included in the new array - If the function returns
false
, the element is excluded - Once all elements are processed, the new array is returned
Practical Example: Filtering Data
const products = [
{ id: 1, name: 'Laptop', price: 999.99, inStock: true },
{ id: 2, name: 'Phone', price: 699.99, inStock: false },
{ id: 3, name: 'Tablet', price: 399.99, inStock: true },
{ id: 4, name: 'Watch', price: 199.99, inStock: true }
];
// Filter products that are in stock
const availableProducts = products.filter(product => product.inStock);
console.log(availableProducts);
/* Output:
[
{ id: 1, name: 'Laptop', price: 999.99, inStock: true },
{ id: 3, name: 'Tablet', price: 399.99, inStock: true },
{ id: 4, name: 'Watch', price: 199.99, inStock: true }
]
*/
// Filter products that are in stock AND less than $500
const affordableProducts = products.filter(product => product.inStock && product.price < 500);
console.log(affordableProducts);
/* Output:
[
{ id: 3, name: 'Tablet', price: 399.99, inStock: true },
{ id: 4, name: 'Watch', price: 199.99, inStock: true }
]
*/
The Reduce Method
The reduce()
method executes a reducer function on each element of the array, resulting in a single output value.
Syntax
const result = array.reduce(callback(accumulator, currentValue[, index[, array]]) {
// return updated accumulator
}, initialValue);
Basic Example
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 15 (1 + 2 + 3 + 4 + 5)
Step-by-step Explanation
- The
reduce()
method takes a callback function and an initial value (0 in this case) - The callback receives two main arguments:
accumulator
: The accumulated value from previous iterationscurrent
: The current element being processed
- In the first iteration,
accumulator
is the initial value (0) andcurrent
is the first array element (1) - The function returns 0 + 1 = 1, which becomes the new accumulator
- In the second iteration,
accumulator
is 1 andcurrent
is 2, resulting in 1 + 2 = 3 - This process continues until all elements are processed
- The final accumulator value is returned
Reduce without an Initial Value
If no initial value is provided, the first element of the array is used as the initial accumulator and the iteration starts from the second element:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, current) => accumulator + current);
// First iteration: accumulator = 1, current = 2
// Second iteration: accumulator = 3, current = 3
// etc.
console.log(sum); // 15
Practical Examples
Creating an Object from an Array
const pets = ['dog', 'cat', 'dog', 'fish', 'cat', 'dog', 'fish'];
const petCounts = pets.reduce((counts, pet) => {
counts[pet] = (counts[pet] || 0) + 1;
return counts;
}, {});
console.log(petCounts);
// { dog: 3, cat: 2, fish: 2 }
Calculating Total Price with Tax
const cartItems = [
{ name: 'Laptop', price: 999.99, quantity: 1 },
{ name: 'Headphones', price: 99.99, quantity: 2 },
{ name: 'Mouse', price: 29.99, quantity: 1 }
];
const totalWithTax = cartItems.reduce((total, item) => {
const itemTotal = item.price * item.quantity;
return total + itemTotal;
}, 0) * 1.08; // Applying 8% tax
console.log(`Total with tax: $${totalWithTax.toFixed(2)}`);
// Total with tax: $1331.59
Chaining Array Methods
One of the most powerful aspects of map
, filter
, and reduce
is the ability to chain them together for more complex operations.
Example: Calculate Average Price of In-stock Items
const products = [
{ id: 1, name: 'Laptop', price: 999.99, inStock: true },
{ id: 2, name: 'Phone', price: 699.99, inStock: false },
{ id: 3, name: 'Tablet', price: 399.99, inStock: true },
{ id: 4, name: 'Watch', price: 199.99, inStock: true },
{ id: 5, name: 'Headphones', price: 99.99, inStock: true }
];
const averageInStockPrice = products
.filter(product => product.inStock)
.map(product => product.price)
.reduce((avg, price, _, array) => avg + price / array.length, 0);
console.log(`Average price of in-stock items: $${averageInStockPrice.toFixed(2)}`);
// Average price of in-stock items: $424.99
Step-by-step Explanation of Chaining
filter()
creates a new array with only the in-stock productsmap()
transforms that array into an array of just the pricesreduce()
calculates the average price by summing each price divided by the total count
Real-world Application: Data Processing Pipeline
Here's a real-world example of processing user data:
const users = [
{ id: 1, name: 'John', age: 25, active: true, purchases: [100, 200, 300] },
{ id: 2, name: 'Jane', age: 17, active: true, purchases: [50, 75] },
{ id: 3, name: 'Bob', age: 32, active: false, purchases: [250, 300, 150] },
{ id: 4, name: 'Mary', age: 28, active: true, purchases: [500] },
{ id: 5, name: 'Alex', age: 15, active: true, purchases: [25, 25, 30] }
];
// Get the total purchases of active adult users
const totalAdultActivePurchases = users
.filter(user => user.active && user.age >= 18) // Filter active adults
.map(user => user.purchases.reduce((sum, val) => sum + val, 0)) // Sum each user's purchases
.reduce((total, userTotal) => total + userTotal, 0); // Sum all user totals
console.log(`Total purchases by active adults: $${totalAdultActivePurchases}`);
// Total purchases by active adults: $1100
Summary
JavaScript's map()
, filter()
, and reduce()
methods are powerful tools for functional programming:
- map(): Transforms array elements into something new (one-to-one)
- filter(): Selects elements that meet specific criteria
- reduce(): Combines all elements into a single value or structure
These methods make your code:
- More readable and expressive
- Less prone to bugs (avoids mutations)
- More maintainable (separates what to do from how to do it)
- More concise (eliminates need for many
for
loops)
Additional Resources
- MDN Web Docs - Array.prototype.map()
- MDN Web Docs - Array.prototype.filter()
- MDN Web Docs - Array.prototype.reduce()
Exercises
- Use
map()
to create an array of squares from an array of numbers. - Use
filter()
to extract all prime numbers from an array of integers. - Use
reduce()
to find the longest string in an array of strings. - Chain these methods to find the sum of squares of positive numbers from a mixed array.
- Create a function that uses
reduce()
to group objects by a specified property.
Happy coding!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)