Array Methods and Functional Programming
Mastering array manipulation with map, filter, reduce and other methods
Challenge
Section titled “Challenge”Convert an array of user objects into a single object mapping user IDs to user names, filtering only active users. How can you do this with a single array operation?
Explanation
Section titled “Explanation”Array methods like map, filter, and reduce are foundational to functional programming in JavaScript. They allow you to transform data in declarative, composable ways.
Solution: Reduce with Filter
Section titled “Solution: Reduce with Filter”const users = [ { id: 1, name: 'Alice', active: true }, { id: 2, name: 'Bob', active: false }, { id: 3, name: 'Charlie', active: true }, { id: 4, name: 'David', active: false }];
// ❌ Imperative approachconst result1 = {};for (const user of users) { if (user.active) { result1[user.id] = user.name; }}
// ✅ Functional approachconst result2 = users .filter(user => user.active) .reduce((acc, user) => ({ ...acc, [user.id]: user.name }), {});
// ✅ One-pass reduceconst result3 = users.reduce((acc, user) => { if (user.active) { acc[user.id] = user.name; } return acc;}, {});
console.log(result3); // { 1: 'Alice', 3: 'Charlie' }Core Array Methods
Section titled “Core Array Methods”// map: Transform each elementconst numbers = [1, 2, 3, 4, 5];const doubled = numbers.map(n => n * 2);console.log(doubled); // [2, 4, 6, 8, 10]
// filter: Keep elements matching conditionconst evens = numbers.filter(n => n % 2 === 0);console.log(evens); // [2, 4]
// reduce: Accumulate into single valueconst sum = numbers.reduce((acc, n) => acc + n, 0);console.log(sum); // 15
// find: Get first matching elementconst firstEven = numbers.find(n => n % 2 === 0);console.log(firstEven); // 2
// findIndex: Get index of first matchconst index = numbers.findIndex(n => n % 2 === 0);console.log(index); // 1
// some: Check if any element matchesconst hasEven = numbers.some(n => n % 2 === 0);console.log(hasEven); // true
// every: Check if all elements matchconst allPositive = numbers.every(n => n > 0);console.log(allPositive); // true
// includes: Check if contains valueconsole.log([1, 2, 3].includes(2)); // trueAdvanced Reduce Patterns
Section titled “Advanced Reduce Patterns”// Grouping by propertyconst items = [ { category: 'fruit', name: 'apple' }, { category: 'fruit', name: 'banana' }, { category: 'vegetable', name: 'carrot' }];
const grouped = items.reduce((acc, item) => { const key = item.category; acc[key] = acc[key] || []; acc[key].push(item.name); return acc;}, {});
console.log(grouped);// { fruit: ['apple', 'banana'], vegetable: ['carrot'] }
// Counting occurrencesconst words = ['apple', 'banana', 'apple', 'carrot', 'banana', 'apple'];const counts = words.reduce((acc, word) => { acc[word] = (acc[word] || 0) + 1; return acc;}, {});
console.log(counts);// { apple: 3, banana: 2, carrot: 1 }
// Flattening arraysconst 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 use flat()console.log(nested.flat()); // [1, 2, 3, 4, 5, 6]Chaining Array Methods
Section titled “Chaining Array Methods”// Efficient data transformation pipelineconst data = [ { id: 1, score: 45, subject: 'math' }, { id: 2, score: 85, subject: 'math' }, { id: 3, score: 92, subject: 'english' }, { id: 4, score: 78, subject: 'math' }, { id: 5, score: 65, subject: 'english' }];
const result = data .filter(item => item.score >= 70) // Pass/fail threshold .filter(item => item.subject === 'math') // Math only .map(item => ({ name: `Student ${item.id}`, score: item.score })) .sort((a, b) => b.score - a.score) // Highest first .slice(0, 2); // Top 2
console.log(result);// [// { name: 'Student 2', score: 85 },// { name: 'Student 4', score: 78 }// ]Performance Considerations
Section titled “Performance Considerations”// Create once, reuseconst numbers = Array.from({ length: 1000000 }, (_, i) => i);
// ❌ Chain creates intermediate arraysconst result1 = numbers .filter(n => n % 2 === 0) // Creates new array .map(n => n * 2) // Creates another array .slice(0, 10); // Filters to 10
// ✅ Reduce in one pass (more efficient)const result2 = numbers.reduce((acc, n) => { if (acc.length >= 10) return acc; if (n % 2 === 0) acc.push(n * 2); return acc;}, []);
// ✅ Use for loop for max performance if neededconst result3 = [];for (let i = 0; i < numbers.length && result3.length < 10; i++) { if (numbers[i] % 2 === 0) { result3.push(numbers[i] * 2); }}Modern Methods
Section titled “Modern Methods”// flatMap: map then flattenconst sentences = ['hello world', 'how are you'];const words = sentences.flatMap(s => s.split(' '));console.log(words); // ['hello', 'world', 'how', 'are', 'you']
// toReversed (ES2023): Create reversed copyconst arr = [1, 2, 3];const reversed = arr.toReversed();console.log(arr); // [1, 2, 3] - original unchangedconsole.log(reversed); // [3, 2, 1]
// toSorted (ES2023): Create sorted copyconst unsorted = [3, 1, 2];const sorted = unsorted.toSorted();console.log(unsorted); // [3, 1, 2] - original unchangedconsole.log(sorted); // [1, 2, 3]
// with (ES2023): Create modified copyconst original = ['a', 'b', 'c'];const modified = original.with(1, 'B');console.log(original); // ['a', 'b', 'c'] - unchangedconsole.log(modified); // ['a', 'B', 'c']Practical Example: Data Processing Pipeline
Section titled “Practical Example: Data Processing Pipeline”// Process sales dataconst sales = [ { product: 'A', region: 'North', amount: 100, date: '2024-01-15' }, { product: 'B', region: 'South', amount: 150, date: '2024-01-20' }, { product: 'A', region: 'North', amount: 200, date: '2024-02-10' }, { product: 'C', region: 'East', amount: 75, date: '2024-02-15' }, { product: 'B', region: 'West', amount: 125, date: '2024-03-05' }];
// Analyze sales by productconst analysis = sales .reduce((acc, sale) => { if (!acc[sale.product]) { acc[sale.product] = { product: sale.product, total: 0, count: 0, regions: new Set() }; } acc[sale.product].total += sale.amount; acc[sale.product].count += 1; acc[sale.product].regions.add(sale.region); return acc; }, {});
// Transform to array and calculate averageconst summary = Object.values(analysis) .map(item => ({ ...item, average: item.total / item.count, regions: Array.from(item.regions) })) .sort((a, b) => b.total - a.total);
console.log(summary);