Week 5: Arrays & Array Methods

Every loop you've written so far has been a manual for loop. This week replaces most of them with array methods purpose-built for the exact job: transforming a list, filtering it down, folding it into one value, or just asking a yes/no question about it. Reaching for the right one by name is a skill in itself — this week builds it.

Phase 3 of 8 Week 5 of 14 ~3–4 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Choose between map, filter and reduce based on the shape of the answer you need
  • Use find, some and every to answer "which one" and "is any/all" questions
  • Chain array methods into a readable pipeline instead of one dense loop

1. map, filter & reduce

These three cover the vast majority of everyday array work. Each one takes a callback and returns something different-shaped, which is exactly how to tell them apart:

map: same length, transformed
const prices = [10, 20, 30];
const withTax = prices.map((price) => price * 1.08);
console.log(withTax); // [10.8, 21.6, 32.4] -- one output per input
filter: shorter (or equal), same shape
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((n) => n % 2 === 0);
console.log(evens); // [2, 4, 6] -- only the elements that passed the test
reduce: folds down to one value
const cart = [{ price: 10 }, { price: 20 }, { price: 30 }];
const total = cart.reduce((sum, item) => sum + item.price, 0);
console.log(total); // 60 -- the whole array collapsed into a single number

map always returns an array of the same length as the original — one transformed value per input. filter returns an array that's the same length or shorter, keeping only elements where the callback returned true. reduce is the most flexible: it carries an accumulator through every element and can produce a number, a string, an object, or even a brand-new array — whatever the callback and starting value (0 above) build toward.

None of these mutate the original array

prices, numbers and cart above are all completely unchanged after these calls. map, filter and reduce always return something new, which is exactly why they pair so well with the immutability habits Week 6 builds on.

2. find, some, every & includes

A different family of methods, for when the question isn't "transform this list" but "tell me something about it":

find: the first match itself, or undefined
const users = [{ id: 1, name: "Ana" }, { id: 2, name: "Ben" }];
const user = users.find((u) => u.id === 2);
console.log(user); // { id: 2, name: "Ben" }
some & every: yes/no questions
const scores = [72, 88, 95, 61];

const hasFailingScore = scores.some((s) => s < 60);   // false -- at least one below 60?
const allPassing = scores.every((s) => s >= 60);       // true -- every one at least 60?
includes: simplest membership check
const fruits = ["apple", "banana", "cherry"];
console.log(fruits.includes("banana")); // true -- just true/false, no callback needed

find answers "which one" and stops scanning the moment it finds a match. some and every both answer yes/no questions and also short-circuit — some stops at the first success, every stops at the first failure. includes is the plainest of the group: no callback, just "is this exact value anywhere in here?"

3. forEach vs. map

These two look almost identical and are easy to reach for interchangeably — but they exist for genuinely different purposes:

forEach: side effects, no return value
const items = ["pen", "notebook", "eraser"];

const result = items.forEach((item) => console.log(item));
console.log(result); // undefined -- forEach never returns anything useful

forEach runs a callback for every element and always returns undefined — it exists purely for side effects, like logging or pushing into an outside array. map exists to produce a new array; using it just to log something (and throwing away the array it builds) works, but confuses readers about the code's intent. A simple rule: if you're not using the return value, reach for forEach. If you need a transformed array back, reach for map.

4. sort & the Comparator

Array.prototype.sort() has a well-known trap: it sorts elements as strings by default, which breaks silently on numbers:

the default-sort trap
const numbers = [10, 1, 21, 2];
console.log(numbers.sort()); // [1, 10, 2, 21] -- WRONG, sorted as text ("10" < "2")
the fix: a comparator function
const ascending = [10, 1, 21, 2].sort((a, b) => a - b);
console.log(ascending); // [1, 2, 10, 21] -- correct numeric order

const descending = [10, 1, 21, 2].sort((a, b) => b - a);
console.log(descending); // [21, 10, 2, 1]

A comparator returns a negative number when a should come first, a positive number when b should come first, and 0 if they're equal — a - b does exactly that for ascending numeric order, and flipping it to b - a reverses it. Also worth knowing: sort() mutates the original array in place. Spread it into a copy first ([...numbers].sort(...)) if the original order needs to survive.

5. Chaining Array Methods

Because map and filter both return a new array, calls can be chained directly onto each other — building a pipeline that reads top-to-bottom as a sequence of steps:

a chained pipeline
const orders = [
  { item: "Pen", price: 10, qty: 3, inStock: true },
  { item: "Mug", price: 150, qty: 2, inStock: false },
  { item: "Bag", price: 500, qty: 1, inStock: true },
];

const totalInStockValue = orders
  .filter((order) => order.inStock)                   // keep only what's in stock
  .map((order) => order.price * order.qty)             // turn each into a line total
  .reduce((sum, lineTotal) => sum + lineTotal, 0);      // fold into one number

console.log(totalInStockValue); // 530

Read right to left through the logic, but top to bottom through the code: filter down to what qualifies, map each survivor to the value that actually matters, then reduce those values into a final answer. This chained shape is one of the most common patterns you'll see in real JavaScript — worth being fully comfortable reading and writing before Week 6 builds on it further.

Each link in the chain walks the whole array again

A three-step chain like the one above loops over the data three separate times, not once. For everyday list sizes this is completely fine and far more readable than one dense hand-rolled loop — but it's worth knowing this trade-off exists once you're working with very large arrays where a single pass matters.

6. Hands-on Exercise

Hands-on

Build a small order-analytics report

Combine map, filter, reduce, find and sort on one array of order objects.

Requirements:

  1. Create an array of at least 6 order objects, each with item, price, qty and category (use 2–3 different categories).
  2. Write a chained pipeline that returns the total value of orders in a single chosen category (filtermapreduce).
  3. Use find to locate the single most expensive individual order (by price), and log its item name.
  4. Use every to check whether every order has a qty greater than 0, and some to check whether any order's total line value (price * qty) exceeds 1000.
  5. Produce a version of the array sorted by price descending, using a comparator, without mutating the original array.
Hint

For step 3, reduce can find a max just as well as find can locate a specific one — but find is the right tool when you're checking a condition (like order.price === highestPrice) rather than computing one from scratch.

7. Knowledge Check

Four quick questions. Expand each to check your answer.

Q1

You need the total price of every item in a cart, as a single number. Which method is the right final step: map, filter, or reduce?

reduce. map and filter both return arrays, not a single value — only reduce is built to fold a whole array down into one final result, carrying a running total (the accumulator) through every element.

Q2

What's the practical difference between array.find(...) and array.filter(...) when the same condition would match more than one element?

find returns only the first matching element itself (not an array), and stops scanning the moment it finds it. filter keeps scanning the whole array and returns every matching element as a new array — even if only one element matches, filter still returns an array (with one item in it), not the element itself.

Q3

Why does [10, 1, 21, 2].sort() (with no comparator) produce [1, 10, 2, 21] instead of numeric order?

Without a comparator, sort() converts every element to a string and compares them alphabetically — and as strings, "10" comes before "2" because "1" is alphabetically earlier than "2". Passing a comparator like (a, b) => a - b overrides this default and forces a real numeric comparison instead.

Q4

You call array.map(item => console.log(item)) purely to print each item, and never use the array it returns. What should you use instead, and why?

forEach. It exists specifically for side effects like logging, where no new array is needed — using map here still works, but it builds and immediately discards a whole array of undefined values (since console.log returns undefined), which misleads anyone reading the code into thinking a transformed array matters.