Data Structures and Algorithms (DSA)  

Chapter 16: Functional Programming: Map, Filter, and Reduce

While classes deal with objects and state, Functional Programming (FP) focuses on functions and immutability (not changing data directly). Modern JavaScript embraces FP, especially when dealing with data collections like arrays. This chapter covers the three most powerful array methods that are cornerstones of FP: map, filter, and reduce.

Core FP Concepts

  1. Immutability: Data should not be changed after creation. Instead, create new data structures.

  2. Pure Functions: Functions that always return the same output for the same input, and have no side effects (like changing global variables or modifying external data).

  3. Higher-Order Functions: Functions that take other functions as arguments (like map, filter, reduce).

1. map(): Transforming Data

The map() method creates a new array populated with the results of calling a provided function on every element in the calling array. It is used for transformation.

JavaScript

const numbers = [1, 4, 9, 16];

// Goal: Create a new array where each number is doubled.
const doubled = numbers.map(num => num * 2);

console.log(doubled); // Output: [2, 8, 18, 32]
console.log(numbers); // Original array is unchanged (Immutability)

// Example with objects: Extracting specific properties
const users = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 }
];

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

2. filter(): Selecting Data

The filter() method creates a new array containing all elements that pass a test implemented by the provided function. It is used for selection. The function must return a boolean (true to keep, false to discard).

JavaScript

const ages = [12, 18, 25, 6];

// Goal: Create an array of only users who are 18 or older.
const adults = ages.filter(age => age >= 18);

console.log(adults); // Output: [18, 25]

// Example with objects:
const products = [
    { name: 'Shirt', price: 50 },
    { name: 'Socks', price: 10 },
    { name: 'Jeans', price: 80 }
];

const expensiveProducts = products.filter(p => p.price > 40);
console.log(expensiveProducts); // Output: [{ name: 'Shirt', price: 50 }, { name: 'Jeans', price: 80 }]

3. reduce(): Aggregating Data

The reduce() method executes a reducer function (callback) on each element of the array, resulting in a single output value. It is used for aggregation (e.g., summing, counting, flattening).

The reducer function takes four arguments: (accumulator, currentValue, index, array). The accumulator carries the result across each iteration.

JavaScript

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

// Goal: Calculate the sum of all numbers.
// 0 is the optional 'initialValue' of the accumulator.
const sum = numbers.reduce((total, num) => total + num, 0);

console.log(sum); // Output: 10 (1+2+3+4)

// Example with objects: Counting items
const items = [{ cost: 10 }, { cost: 5 }, { cost: 15 }];

// Goal: Calculate the total cost.
const totalCost = items.reduce((acc, item) => acc + item.cost, 0);
console.log(totalCost); // Output: 30

Chaining Methods

A key advantage of FP is that since map and filter both return new arrays, you can easily chain these methods together to perform complex data manipulations in a highly readable way.

JavaScript

const transactions = [100, -50, 200, -30, 400];

// Goal: Sum up only the positive (deposits) transactions.
const totalDeposits = transactions
    .filter(t => t > 0) // [100, 200, 400]
    .reduce((total, deposit) => total + deposit, 0); // 700

console.log(totalDeposits); // Output: 700