Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 6

Transforming Arrays with Iteration, Map, Filter, and Reduce

Recommended resources

Welcome back. In the previous lesson, you defined functions, passed arguments into parameters, returned values, and used local scope to keep each function’s work contained. Those ideas are the foundation for this lesson: JavaScript’s array tools work by calling a function for each item in a list.

You will learn to process arrays with ordinary iteration, forEach, map, filter, and reduce. By the end, you should be able to look at a list-processing task—such as validating a set of simulated payment amounts or adding a list of fees—and select the method that produces the right kind of result. Plan for roughly 45 minutes including the short video, reading, and coding.


Arrays are ordered lists

An array holds an ordered sequence of values. Values may be numbers, strings, booleans, or, later, objects representing data such as transactions and wallet information.

const amounts = [125, 80, 210, 40];

The values have positions called indexes. Indexes start at 0:

console.log(amounts[0]); // 125
console.log(amounts[2]); // 210
console.log(amounts.length); // 4

Most array work involves iteration: visiting each item in sequence.

Iterating with a for loop

You used this pattern in the earlier lesson. The counter index begins at 0, continues while it is smaller than the array’s length, and increases after each iteration.

const amounts = [125, 80, 210, 40];

for (let index = 0; index < amounts.length; index++) {
  console.log("Amount:", amounts[index]);
}

Output:

Amount: 125
Amount: 80
Amount: 210
Amount: 40

This form is useful when you need the index itself. But if you only need each value, for...of is more direct:

for (const amount of amounts) {
  console.log("Amount:", amount);
}

Here, amount takes the value of each array item in turn. Since it receives a new value on each iteration and is not reassigned, const is appropriate.

Building a new array manually

Suppose we want a new array in which every amount is doubled. A loop can do that:

const amounts = [125, 80, 210, 40];
const doubledAmounts = [];

for (const amount of amounts) {
  doubledAmounts.push(amount * 2);
}

console.log(doubledAmounts);

Output:

[ 250, 160, 420, 80 ]

push() adds a value to the end of an array. This approach is correct—and understanding it helps you understand what the specialized methods do—but JavaScript gives us clearer tools when our intention is specifically to transform, select, or combine array values.

forEach: iterate for an effect, not a result

Use forEach() when you want to do something once per item, such as display information. It calls your function for each value but does not build and return a useful new array.

const amounts = [125, 80, 210, 40];

amounts.forEach((amount, index) => {
  console.log("Request " + index + ": " + amount);
});

The function inside forEach is a callback: a function you give to another function so that it can call it later. In this example, JavaScript calls the callback four times.

The arrow-function syntax:

(amount, index) => {
  console.log("Request " + index + ": " + amount);
}

is a compact way to write a function. It is similar in purpose to:

function showRequest(amount, index) {
  console.log("Request " + index + ": " + amount);
}

A key rule:

  • Use forEach for actions such as logging.
  • Do not use it when you need to produce a transformed array or a calculated total.


map: transform every item

Use map() when every source item should become a corresponding result item.

const amounts = [125, 80, 210, 40];

const doubledAmounts = amounts.map((amount) => {
  return amount * 2;
});

console.log(doubledAmounts);

Output:

[ 250, 160, 420, 80 ]

map() calls the callback once per item. Crucially, the callback’s return value becomes the corresponding item in the new array.

Because the callback contains only one expression, we can use the shorter arrow-function form:

const doubledAmounts = amounts.map(amount => amount * 2);

An arrow function without curly braces implicitly returns its expression. These two lines are equivalent:

amount => amount * 2
amount => {
  return amount * 2;
}

map() has two defining characteristics:

  1. It returns a new array.
  2. The result has the same number of items and order as the original array.
The image shows `map()` turning each hiker’s starting energy value into a halved value. Each input item produces exactly one transformed output item in the same position.

For example, map() can also turn numbers into display strings:

const amounts = [125, 80, 210];

const labels = amounts.map(amount => "Amount: " + amount);

console.log(labels);

Output:

[ 'Amount: 125', 'Amount: 80', 'Amount: 210' ]

A common map() mistake: forgetting return

If you use curly braces, you must write return yourself:

const amounts = [125, 80, 210];

const doubledAmounts = amounts.map(amount => {
  amount * 2;
});

console.log(doubledAmounts);

This gives:

[ undefined, undefined, undefined ]

The calculation occurred, but it was not returned to map(). Correct it like this:

const doubledAmounts = amounts.map(amount => {
  return amount * 2;
});


filter: keep only items that pass a test

Use filter() when you need a subset of an array. Its callback must return a boolean:

  • true means keep this item.
  • false means omit this item.

Imagine a list of simulated transfer requests. A request amount must be positive before it can proceed:

const requestedAmounts = [0, 125, -20, 80, 40];

const validAmounts = requestedAmounts.filter(amount => amount > 0);

console.log(validAmounts);

Output:

[ 125, 80, 40 ]

The original array still has all five values:

console.log(requestedAmounts);
[ 0, 125, -20, 80, 40 ]

filter() did not replace the source array. Instead, it created a new one containing only values for which the condition was true.

Compare these callbacks carefully:

amounts.map(amount => amount * 2);

The callback returns a new value for every item.

amounts.filter(amount => amount > 0);

The callback returns a true/false decision about whether to keep each original item.

A useful way to read filter code is as a sentence:

const affordable = amounts.filter(amount => amount <= 100);

“Create affordable from the amounts for which the amount is at most 100.”

Neither map() nor filter() changes the number array you call them on. This makes them safer to reason about: preserve the raw input, then assign each derived result a clear name.



reduce: combine an array into one result

reduce() is different from map() and filter().

  • map() returns an array of transformed values.
  • filter() returns an array of selected values.
  • reduce() returns one accumulated result.

A common use is adding values together:

const fees = [3, 5, 2];

const totalFee = fees.reduce((sum, fee) => {
  return sum + fee;
}, 0);

console.log(totalFee);

Output:

10

The 0 at the end is the initial value. It tells JavaScript that sum should begin at 0.

The calculation unfolds like this:

Callback call sum before Current fee Returned value
First 0 3 3
Second 3 5 8
Third 8 2 10

Each returned value becomes the next call’s sum. At the end, reduce() returns the final accumulated result: 10.

The compact version is:

const totalFee = fees.reduce((sum, fee) => sum + fee, 0);

Always provide an initial value while learning reduce():

const totalFee = fees.reduce((sum, fee) => sum + fee, 0);

This is predictable even for an empty array:

const noFees = [];

const totalFee = noFees.reduce((sum, fee) => sum + fee, 0);

console.log(totalFee); // 0

Without an initial value, reducing an empty array causes a runtime error. More broadly, the initial value establishes what kind of result you are building: 0 for a numeric sum, "" for a string, or—later—an empty object or array for more structured results.

8 Must Know JavaScript Array Methods

Watch “8 Must Know JavaScript Array Methods” from Web Dev Simplified to reinforce the distinction between selecting, transforming, iterating, and accumulating. The examples use product-like data, but the callback patterns are the same ones you will use with data from APIs and dApp interfaces.

Watch filter and map first. Notice that filter returns a boolean decision while map returns the transformed item. Then skip to forEach to see why logging with forEach does not create a new result array. Finish with reduce, focusing on the order of the accumulator and current-item parameters and the role of the initial value.



Choose the method by the result you need

The method name matters less than the question: what should come out of this operation?

Need Best starting tool Callback should return Result
Visit items and log or perform an action for...of or forEach Nothing useful for forEach No derived result
Change every item map The transformed item New array, same length
Keep only matching items filter true or false New array, possibly shorter
Combine all items into one result reduce The next accumulator value One value
Need index control or more complex flow for loop Depends on your code Depends on your code

These methods also compose naturally. Start with readable intermediate names:

const requestedAmounts = [0, 125, -20, 80, 40];

const validAmounts = requestedAmounts.filter(amount => amount > 0);

const doubledAmounts = validAmounts.map(amount => amount * 2);

const total = doubledAmounts.reduce(
  (sum, amount) => sum + amount,
  0
);

console.log(total);

Output:

490

Read the flow from top to bottom:

  1. Keep positive amounts: [125, 80, 40]
  2. Double them: [250, 160, 80]
  3. Add them: 490

You may eventually see this written as a single chain. For now, the named intermediate arrays make the logic easier to inspect and debug:

const total = requestedAmounts
  .filter(amount => amount > 0)
  .map(amount => amount * 2)
  .reduce((sum, amount) => sum + amount, 0);

Both versions produce the same value. Prefer the multi-step version when learning or when each stage has a meaningful name.

Array methods

Read the relevant parts of “Array methods” from javascript.info as a reference for the precise behavior of forEach, filter, map, and reduce. Its reduce walkthrough is particularly useful if the accumulator still feels abstract.

In the “Iterate: forEach” section, read the forEach explanation and connect it to the rule that forEach is for per-item actions, not a derived result. Then read the “filter” subsection and the “Transform an array” subsection through filter and map. Focus on the different purpose of each callback: boolean selection for filter, transformed values for map. Finally, in the “reduce/reduceRight” subsection, read the reduce walkthrough. Follow the accumulator from one callback call to the next, and note why an initial value makes empty-array behavior safe.



Build a small array-processing script

Create a file named array-report.js. The values are deliberately simple simulated units, not real Ether or token amounts. Real blockchain applications require careful handling of decimal precision and very large integers; for now, focus on the array logic.

const requestedAmounts = [0, 125, -20, 80, 40];

// Iterate: show every raw request.
requestedAmounts.forEach((amount, index) => {
  console.log("Raw request " + index + ": " + amount);
});

// Filter: keep only positive requests.
const validAmounts = requestedAmounts.filter(amount => amount > 0);

// Map: create a new array of doubled values.
const doubledAmounts = validAmounts.map(amount => amount * 2);

// Reduce: calculate one total from the transformed values.
const totalAmount = doubledAmounts.reduce(
  (sum, amount) => sum + amount,
  0
);

console.log("Valid amounts:", validAmounts);
console.log("Doubled amounts:", doubledAmounts);
console.log("Total:", totalAmount);

Run it from your practice folder:

node array-report.js

Expected output:

Raw request 0: 0
Raw request 1: 125
Raw request 2: -20
Raw request 3: 80
Raw request 4: 40
Valid amounts: [ 125, 80, 40 ]
Doubled amounts: [ 250, 160, 80 ]
Total: 490

As you inspect the output, keep the data flow in view:

requestedAmounts
    -> filter
validAmounts
    -> map
doubledAmounts
    -> reduce
totalAmount

The naming is not cosmetic. In a larger program, clear names let you determine whether a surprising output came from raw input, validation, transformation, or accumulation.



Wrap-up

You can now process lists in several purposeful ways:

  • Arrays are ordered collections indexed from 0.
  • Use for, for...of, or forEach to visit items; forEach is especially suited to actions such as logging.
  • map() creates a new array by returning one transformed result for every input item.
  • filter() creates a new array by retaining only items whose callback returns true.
  • reduce() combines all items into one accumulated result. Supply an initial value such as 0 for a sum.
  • Each method relies on a callback function—directly applying the parameters and return values from the previous lesson.

Next, you will move from lists of plain values to JavaScript objects: creating them, reading and updating properties, and destructuring data. That is the form in which transaction, wallet, and API data usually becomes useful in a JavaScript program.