JavaScript · Syntax · Intermediate

Array methods: map, filter, reduce

10 tasks

Functional array methods for transforming, filtering, and aggregating data without explicit loops.

map, filter, reduce, forEach: implicit return gotcha and mutation warnings

#
**map — transform every element** ```javascript const nums = [1, 2, 3, 4]; // map returns a NEW array — does not modify the original const doubled = nums.map(x => x * 2); // [2, 4, 6, 8] console.log(nums); // [1, 2, 3, 4] — unchanged // map callback gets (element, index, array): const tagged = nums.map((x, i) => `${i}:${x}`); // ['0:1', '1:2', '2:3', '3:4'] // Common mistake — forgetting the implicit return in arrow functions: const bad = nums.map(x => { x * 2 }); // [undefined, undefined, ...] — {} means block const good = nums.map(x => x * 2); // [2, 4, 6, 8] — expression body const good2 = nums.map(x => ({ value: x * 2 })); // return object — wrap in () ``` **filter — keep elements that pass a test** ```javascript const evens = nums.filter(x => x % 2 === 0); // [2, 4] // filter also returns a new array: const words = ['', 'hello', null, 'world', undefined]; const clean = words.filter(Boolean); // ['hello', 'world'] — filter(Boolean) removes falsy ``` **reduce — fold into a single value** ```javascript // reduce(callback, initialValue) // callback gets (accumulator, currentValue, index, array) const sum = nums.reduce((acc, x) => acc + x, 0); // 10 const max = nums.reduce((acc, x) => x > acc ? x : acc, -Infinity); // 4 // Always provide an initial value — without it, reduce fails on empty arrays: [].reduce((acc, x) => acc + x); // TypeError: Reduce of empty array [].reduce((acc, x) => acc + x, 0); // 0 — safe ``` **forEach — side effects only** ```javascript // forEach returns undefined — never use it to build a new array nums.forEach(x => console.log(x)); // prints 1 2 3 4 // BAD: const result = nums.forEach(x => x * 2); // undefined — don't do this // GOOD: use map when you need a new array ``` **Mutation warning: sort() and reverse() modify in place** ```javascript const arr = [3, 1, 4, 1, 5]; // sort and reverse MUTATE the original: arr.sort((a, b) => a - b); // arr is now [1, 1, 3, 4, 5] arr.reverse(); // arr is now [5, 4, 3, 1, 1] // To sort without mutation (ES2023 toSorted/toReversed, or copy first): const sorted = [...arr].sort((a, b) => a - b); // safe — spread copies const rev = arr.toReversed(); // ES2023, returns new array ```

Chaining methods, reduce for grouping, flatMap, and Array.from

#
**Chaining array methods** Because map/filter return new arrays, you can chain them: ```javascript const users = [ { name: 'Alice', age: 25, active: true }, { name: 'Bob', age: 17, active: true }, { name: 'Carol', age: 32, active: false }, { name: 'Dave', age: 28, active: true }, ]; const result = users .filter(u => u.active && u.age >= 18) // keep active adults .map(u => u.name) // extract names .sort(); // alphabetical // ['Alice', 'Dave'] ``` **reduce for grouping** ```javascript const orders = [ { category: 'food', amount: 30 }, { category: 'tech', amount: 200 }, { category: 'food', amount: 15 }, ]; const totals = orders.reduce((acc, order) => { acc[order.category] = (acc[order.category] ?? 0) + order.amount; return acc; }, {}); // { food: 45, tech: 200 } ``` **flatMap — map then flatten one level** ```javascript const sentences = ['hello world', 'foo bar baz']; // map gives array of arrays: sentences.map(s => s.split(' ')); // [['hello','world'], ['foo','bar','baz']] // flatMap maps then flattens one level: sentences.flatMap(s => s.split(' ')); // ['hello', 'world', 'foo', 'bar', 'baz'] // flatMap is also useful for producing variable-length outputs: const nums = [1, 2, 3]; nums.flatMap(x => x % 2 === 0 ? [x, x * 10] : [x]); // [1, 2, 20, 3] ``` **Array.from — create arrays from other things** ```javascript // From a NodeList (DOM elements) Array.from(document.querySelectorAll('li')) .map(el => el.textContent); // From a Set (deduplication) const unique = Array.from(new Set([1, 2, 2, 3, 3])); // [1, 2, 3] // From a string Array.from('hello'); // ['h', 'e', 'l', 'l', 'o'] // With a mapping function (second argument): Array.from({ length: 5 }, (_, i) => i * 2); // [0, 2, 4, 6, 8] ```

find/some/every, flat, mutation reference table, includes vs indexOf

#
**find, findIndex, some, every** ```javascript const users = [ { id: 1, name: 'Alice', age: 25 }, { id: 2, name: 'Bob', age: 17 }, { id: 3, name: 'Carol', age: 32 }, ]; // find — first match, or undefined users.find(u => u.id === 2); // { id: 2, name: 'Bob', age: 17 } users.find(u => u.age > 50); // undefined // findIndex — index of first match, or -1 users.findIndex(u => u.name === 'Carol'); // 2 // some — true if at least one matches users.some(u => u.age < 18); // true (Bob is 17) // every — true if all match users.every(u => u.age >= 18); // false (Bob is 17) ``` **flat and flat(Infinity)** ```javascript const nested = [1, [2, 3], [4, [5, 6]]]; nested.flat(); // [1, 2, 3, 4, [5, 6]] — one level nested.flat(2); // [1, 2, 3, 4, 5, 6] — two levels nested.flat(Infinity); // fully flatten, no matter how deep ``` **Mutation vs immutability reference** ``` Method Returns new array? Mutates original? ────────────── ───────────────── ───────────────── map ✅ new array ❌ no filter ✅ new array ❌ no reduce ✅ single value ❌ no flatMap ✅ new array ❌ no flat ✅ new array ❌ no slice ✅ new array ❌ no concat ✅ new array ❌ no sort ⚠ same reference ✅ yes — sorts in place reverse ⚠ same reference ✅ yes — reverses in place splice returns removed ✅ yes — modifies array push/pop returns item/length ✅ yes shift/unshift returns item/length ✅ yes fill ⚠ same reference ✅ yes toSorted ✅ new array ❌ no (ES2023) toReversed ✅ new array ❌ no (ES2023) ``` **includes, indexOf, at** ```javascript [1, 2, 3].includes(2); // true [1, 2, NaN].includes(NaN); // true (unlike indexOf!) [1, 2, 3].indexOf(2); // 1 [1, 2, NaN].indexOf(NaN); // -1 (uses ===, NaN !== NaN) // at() — negative index support const arr = [10, 20, 30, 40]; arr.at(-1); // 40 — last element arr.at(-2); // 30 — second to last ```
01

Double the values

#

Write a function that takes an array of numbers and returns a new array where each number is doubled. Use the map() method.

function doubleValues(numbers) {

}

console.log(doubleValues([1, 2, 3, 4, 5]));
Solution
function doubleValues(numbers) {
    return numbers.map(n => n * 2);
}

console.log(doubleValues([1, 2, 3, 4, 5]));
02

Keep the positives

#

Write a function that takes an array of numbers and returns only the positive ones. Use the filter() method.

function keepPositives(numbers) {

}

console.log(keepPositives([3, -1, 4, -1, -5, 9, -2, 6]));
Solution
function keepPositives(numbers) {
    return numbers.filter(n => n > 0);
}

console.log(keepPositives([3, -1, 4, -1, -5, 9, -2, 6]));
03

Sum of an array

#

Write a function that takes an array of numbers and returns their sum. Use the reduce() method.

function sumArray(numbers) {

}

console.log(sumArray([1, 2, 3, 4, 5]));
Solution
function sumArray(numbers) {
    return numbers.reduce((acc, n) => acc + n, 0);
}

console.log(sumArray([1, 2, 3, 4, 5]));
04

Words longer than N

#

Write a function that takes an array of strings and a minimum length, and returns only the strings longer than that length.

function longWords(words, minLength) {

}

console.log(longWords(["cat", "elephant", "dog", "hippopotamus"], 4));
Solution
function longWords(words, minLength) {
    return words.filter(w => w.length > minLength);
}

console.log(longWords(["cat", "elephant", "dog", "hippopotamus"], 4));
05

Names to uppercase

#

Write a function that takes an array of strings and returns a new array with each string converted to uppercase.

function toUpperCase(words) {

}

console.log(toUpperCase(["hello", "world", "javascript"]));
Solution
function toUpperCase(words) {
    return words.map(w => w.toUpperCase());
}

console.log(toUpperCase(["hello", "world", "javascript"]));
06

Product of array

#

Write a function that takes an array of numbers and returns the product of all elements (multiply them all together). Use reduce().

function product(numbers) {

}

console.log(product([1, 2, 3, 4, 5]));
Solution
function product(numbers) {
    return numbers.reduce((acc, n) => acc * n, 1);
}

console.log(product([1, 2, 3, 4, 5]));
07

Extract property

#

Write a function that takes an array of objects, each having a `name` property, and returns an array of just the names.

function getNames(people) {

}

const people = [
    { name: "Alice", age: 30 },
    { name: "Bob", age: 25 },
    { name: "Carol", age: 35 },
];
console.log(getNames(people));
Solution
function getNames(people) {
    return people.map(p => p.name);
}

const people = [
    { name: "Alice", age: 30 },
    { name: "Bob", age: 25 },
    { name: "Carol", age: 35 },
];
console.log(getNames(people));
08

Chain: filter then map

#

Write a function that takes an array of numbers, keeps only those greater than 10, and returns the squares of the remaining numbers.

function squaresAboveTen(numbers) {

}

console.log(squaresAboveTen([3, 15, 8, 20, 5, 12]));
Solution
function squaresAboveTen(numbers) {
    return numbers
        .filter(n => n > 10)
        .map(n => n ** 2);
}

console.log(squaresAboveTen([3, 15, 8, 20, 5, 12]));
09

Count by condition

#

Write a function that takes an array of numbers and returns how many of them are even.

function countEven(numbers) {

}

console.log(countEven([1, 2, 3, 4, 5, 6, 7, 8]));
Solution
function countEven(numbers) {
    return numbers.filter(n => n % 2 === 0).length;
}

console.log(countEven([1, 2, 3, 4, 5, 6, 7, 8]));
10

Group by first letter

#

Write a function that takes an array of strings and returns an object where each key is a first letter and the value is an array of all words starting with that letter.

function groupByFirstLetter(words) {

}

const result = groupByFirstLetter(["apple", "banana", "avocado", "blueberry", "cherry"]);
console.log(result);
Solution
function groupByFirstLetter(words) {
    return words.reduce((acc, word) => {
        const letter = word[0];
        if (!acc[letter]) acc[letter] = [];
        acc[letter].push(word);
        return acc;
    }, {});
}

const result = groupByFirstLetter(["apple", "banana", "avocado", "blueberry", "cherry"]);
console.log(result);