Skip to main content
โšก Calmops

Array Methods: map, filter, reduce, forEach

Array Methods: map, filter, reduce, forEach

These four array methods are essential for functional programming in JavaScript. They transform arrays without modifying the original.

forEach()

Executes a function for each array element:

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

numbers.forEach(num => {
    console.log(num);
});
// Output: 1, 2, 3, 4, 5

With Index and Array

const fruits = ["apple", "banana", "orange"];

fruits.forEach((fruit, index, array) => {
    console.log(`${index}: ${fruit}`);
});
// Output:
// 0: apple
// 1: banana
// 2: orange

forEach vs for Loop

// forEach - functional style
numbers.forEach(num => console.log(num));

// for loop - imperative style
for (let i = 0; i < numbers.length; i++) {
    console.log(numbers[i]);
}

// forEach can't break or return

map()

Transforms each element and returns a new array:

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

const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] (unchanged)

Transforming Objects

const users = [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" },
    { id: 3, name: "Charlie" }
];

const names = users.map(user => user.name);
console.log(names); // ["Alice", "Bob", "Charlie"]

Chaining map()

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

const result = numbers
    .map(num => num * 2)
    .map(num => num + 1)
    .map(num => num / 2);

console.log(result); // [1.5, 2.5, 3.5, 4.5, 5.5]

Converting Types

const strings = ["1", "2", "3", "4"];

const numbers = strings.map(str => parseInt(str));
console.log(numbers); // [1, 2, 3, 4]

const booleans = [1, 0, 1, 0].map(num => Boolean(num));
console.log(booleans); // [true, false, true, false]

filter()

Returns a new array with elements that pass a test:

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

const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6]

Filtering Objects

const users = [
    { id: 1, name: "Alice", active: true },
    { id: 2, name: "Bob", active: false },
    { id: 3, name: "Charlie", active: true }
];

const activeUsers = users.filter(user => user.active);
console.log(activeUsers);
// [{ id: 1, name: "Alice", active: true }, { id: 3, name: "Charlie", active: true }]

Removing Duplicates

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

const unique = numbers.filter((num, index, arr) => arr.indexOf(num) === index);
console.log(unique); // [1, 2, 3, 4]

// Or with Set
const unique2 = [...new Set(numbers)];
console.log(unique2); // [1, 2, 3, 4]

Chaining filter()

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

const result = numbers
    .filter(num => num > 3)
    .filter(num => num < 8)
    .filter(num => num % 2 === 0);

console.log(result); // [4, 6]

reduce()

Reduces array to a single value:

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

const sum = numbers.reduce((accumulator, current) => {
    return accumulator + current;
}, 0);

console.log(sum); // 15

Anatomy

array.reduce((accumulator, current, index, array) => {
    // accumulator: accumulated value
    // current: current element
    // index: current index
    // array: the array being reduced
}, initialValue);

Without Initial Value

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

const sum = numbers.reduce((acc, num) => acc + num);
console.log(sum); // 15 (starts with first element)

Counting Occurrences

const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];

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

console.log(counts);
// { apple: 3, banana: 2, orange: 1 }

Flattening Arrays

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

const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
console.log(flat); // [1, 2, 3, 4, 5, 6]

// Or with spread
const flat2 = nested.reduce((acc, arr) => [...acc, ...arr], []);
console.log(flat2); // [1, 2, 3, 4, 5, 6]

Building Objects

const users = [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" },
    { id: 3, name: "Charlie" }
];

const userMap = users.reduce((acc, user) => {
    acc[user.id] = user;
    return acc;
}, {});

console.log(userMap);
// { 1: { id: 1, name: "Alice" }, 2: { id: 2, name: "Bob" }, ... }

Grouping by Property

const users = [
    { name: "Alice", role: "admin" },
    { name: "Bob", role: "user" },
    { name: "Charlie", role: "admin" }
];

const grouped = users.reduce((acc, user) => {
    if (!acc[user.role]) {
        acc[user.role] = [];
    }
    acc[user.role].push(user);
    return acc;
}, {});

console.log(grouped);
// { admin: [Alice, Charlie], user: [Bob] }

Combining Methods

map + filter

const users = [
    { id: 1, name: "Alice", age: 30 },
    { id: 2, name: "Bob", age: 25 },
    { id: 3, name: "Charlie", age: 35 }
];

const adultNames = users
    .filter(user => user.age >= 30)
    .map(user => user.name);

console.log(adultNames); // ["Alice", "Charlie"]

filter + reduce

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

const sumOfEvens = numbers
    .filter(num => num % 2 === 0)
    .reduce((sum, num) => sum + num, 0);

console.log(sumOfEvens); // 12 (2 + 4 + 6)

map + reduce

const items = [
    { name: "apple", price: 1.5, quantity: 3 },
    { name: "banana", price: 0.5, quantity: 2 },
    { name: "orange", price: 2, quantity: 1 }
];

const total = items
    .map(item => item.price * item.quantity)
    .reduce((sum, price) => sum + price, 0);

console.log(total); // 7.5

All Three

const transactions = [
    { type: "income", amount: 1000 },
    { type: "expense", amount: 200 },
    { type: "income", amount: 500 },
    { type: "expense", amount: 100 }
];

const netIncome = transactions
    .filter(t => t.type === "income")
    .map(t => t.amount)
    .reduce((sum, amount) => sum + amount, 0);

console.log(netIncome); // 1500

Practical Examples

Data Processing Pipeline

const rawData = [
    { id: 1, name: "Alice", score: 85 },
    { id: 2, name: "Bob", score: 92 },
    { id: 3, name: "Charlie", score: 78 },
    { id: 4, name: "David", score: 88 }
];

const report = rawData
    .filter(student => student.score >= 80)
    .map(student => ({
        name: student.name,
        grade: student.score >= 90 ? "A" : "B"
    }))
    .reduce((acc, student) => {
        acc[student.grade] = (acc[student.grade] || 0) + 1;
        return acc;
    }, {});

console.log(report); // { A: 1, B: 3 }

Shopping Cart Total

const cart = [
    { product: "Laptop", price: 1000, quantity: 1 },
    { product: "Mouse", price: 25, quantity: 2 },
    { product: "Keyboard", price: 75, quantity: 1 }
];

const total = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
console.log(total); // 1175

Search and Transform

const users = [
    { id: 1, name: "Alice", email: "[email protected]" },
    { id: 2, name: "Bob", email: "[email protected]" },
    { id: 3, name: "Charlie", email: "[email protected]" }
];

const searchResults = users
    .filter(user => user.name.toLowerCase().includes("a"))
    .map(user => ({ name: user.name, email: user.email }));

console.log(searchResults);
// [{ name: "Alice", email: "[email protected]" }, { name: "Charlie", email: "[email protected]" }]

Performance Tips

Use Appropriate Method

// Good - use forEach for side effects
numbers.forEach(num => console.log(num));

// Good - use map to transform
const doubled = numbers.map(num => num * 2);

// Good - use filter to select
const evens = numbers.filter(num => num % 2 === 0);

// Good - use reduce for aggregation
const sum = numbers.reduce((a, b) => a + b, 0);

Avoid Unnecessary Iterations

// Bad - multiple iterations
const result = numbers
    .map(num => num * 2)
    .filter(num => num > 5)
    .map(num => num + 1);

// Better - combine operations
const result2 = numbers.reduce((acc, num) => {
    const doubled = num * 2;
    if (doubled > 5) {
        acc.push(doubled + 1);
    }
    return acc;
}, []);

Summary

  • forEach(): execute function for each element
  • map(): transform elements, return new array
  • filter(): select elements matching condition
  • reduce(): aggregate to single value
  • Chainable: combine methods for complex operations
  • Immutable: don’t modify original array
  • Functional: enables functional programming style

Official Documentation

Next Steps

  1. Callbacks and Asynchronous JavaScript
  2. Promises: Creation, Chaining, Resolution
  3. Async/Await: Modern Asynchronous Programming

Comments