EXERCISE
1The ultimate power move: chain map, filter, and reduce in a single expression. Each step does one small job. Together, they handle complex data transformations.
The three methods are designed to be used together. Each returns a value the next can consume, so a pipeline reads as a description of the work rather than a set of instructions for performing it.
const orders = [
{ item: "book", price: 12, qty: 2, shipped: true },
{ item: "pen", price: 2, qty: 10, shipped: false },
{ item: "lamp", price: 40, qty: 1, shipped: true },
];
const shippedTotal = orders
.filter((o) => o.shipped)
.map((o) => o.price * o.qty)
.reduce((sum, value) => sum + value, 0);
console.log(shippedTotal); // 64
Three lines, three ideas: choose which orders count, work out what each is worth, add them up. Each step can be read on its own, and each can be commented out to see what it contributes.
The equivalent loop does the same work in one pass and mixes all three concerns:
let total = 0;
for (let i = 0; i < orders.length; i++) {
if (orders[i].shipped) {
total += orders[i].price * orders[i].qty;
}
}
console.log(total); // 64
This is not worse code. It is faster, because it walks the array once instead of three times, and for a very large array in a hot path that is the version to write. What it gives up is that you have to read every line to know what any of it does, and a change to the filtering condition means editing the middle of a block that also does arithmetic.
Order the steps so each does the least work:
const cheapTotal = orders
.filter((o) => o.shipped)
.filter((o) => o.price < 20)
.reduce((sum, o) => sum + o.price * o.qty, 0);
console.log(cheapTotal); // 24
Filter before you map or reduce, and put the most selective condition first. The final reduce here does the multiplication itself, which removes a pass without costing any clarity.
A pipeline returning the wrong type is nearly always a missing initial value:
console.log([].reduce((s, n) => s + n, 0)); // 0
An empty array after filtering is a normal outcome, not an error, and the initial value is what keeps it normal. Without it this line throws, and it will throw on the day the filter happens to match nothing.
Pro Tip: Build a chain one step at a time and log the result after each. Most pipeline bugs are a step returning something other than what the next step expects, and one log line finds it immediately.