Basic

Data Patterns (map, filter, find)

Three powerful one-liners do the most common array tasks without a whole for loop: map (transform), filter (keep matches), and find (first match). They're real game code.

What you will see

2 1,2

About 5 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Three powerful one-liners do the most common array tasks without a whole for loop: map transforms every item, filter keeps the matches, and find returns the first match. The finished game runs these every single frame. I want to read them fluently, because being able to read map, filter, and find means I can read almost any game's data code.

1

map takes an array and returns a NEW array with every item changed. The arrow function s => s * 2 means "for each speed s, give me s times two." map never changes the original, it returns a fresh one. I double every speed and print the new array.

const speeds = [340, 360, 420, 500] const doubled = speeds.map(s => s * 2) console.log(doubled.join(' ')) console.log(speeds.join(' '))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
680 720 840 1000 340 360 420 500
doubled is the transformed copy; the original speeds array is completely unchanged. s is the parameter of the arrow function, the item being transformed. map always returns a new array of the same length.
2

filter returns a new array with only the items whose question-function is true. The real game's SpawnController uses this exact pattern every frame: keep the items whose right edge (x + w) is still past the cutoff, drop the ones that scrolled off.

function recycle(items, cutoff) { return items.filter(g => g.x + g.w > cutoff) } const items = [ { x: 50, w: 20 }, { x: -30, w: 20 }, { x: 400, w: 20 } ] console.log(recycle(items, 350).map(o => o.x).join(', '))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
50, 400
Only items A (70) and C (420) are past cutoff 350; B (-10) is dropped. filter returns a shorter array of matches and leaves the original untouched. The finished game's recycle() does exactly this to remove off-screen items.
3

find returns the FIRST item that answers true, or undefined if none match. Unlike filter (an array), find returns one item. The real game uses this in Particles.js to find the first unused particle slot to reuse. I build particles and find the first inactive one.

function Particles() { return [ { active: true }, { active: false }, { active: true } ] } const particles = Particles() const slot = particles.find(p => !p.active) console.log(slot.active)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
false
find stops at the first particle whose active is false, which is the second one. It returns that single item, not an array. If every particle were active, find would return undefined.
4

some and every answer yes/no questions over a whole list, some is true if at least one matches, every is true if all match. They return booleans, not arrays. I check whether any obstacle is a coin and whether all obstacles are coins.

const obstacles = ["spike", "coin", "wall"] console.log(obstacles.some(o => o === "coin")) console.log(obstacles.every(o => o === "coin")) console.log(obstacles.every(o => o !== "pit"))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
true false true
some stops at the first coin and returns true; every sees the spike and returns false; every confirms no item is a pit, so it returns true. some and every are the booleans you reach for when you need a yes/no over a list.
5

map, filter, and find are just a for loop written as one line that never runs out of bounds or forgets to push. I rewrite a raw loop as a filter in one line, keep only active coins, and print the result. This is the exact trade: same work, clearer intent.

const coins = [ { active: true }, { active: false }, { active: true }, { active: false } ] const active = coins.filter(c => c.active) console.log(active.length) console.log(active.map((c, i) => i + 1).join(','))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
2 1,2
filter keeps the two active coins, and the new array is re-indexed 0 and 1. map/filter/find never mutate the original and never go out of bounds, that immutability is what makes them safe and easy to reason about.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A question function is applied to each item; map, filter, and find each produce a new result without touching the original array.
1 Have an array of items
↓
2 Pass a function that inspects or transforms one item
↓
3 map runs it on every item and collects the outputs
↓
4 filter runs it on every item and keeps the trues
↓
5 find stops at the first true and returns that item
Why this works
Why these beat a raw for loop

You could write all of this with a for loop and a result array. You could. But these one-liners say exactly what they mean in one line, and they never run out of bounds or forget to push.

// Instead of this...
const active = [];
for (const c of coins) {
  if (c.active) active.push(c);
}
// ...write this.
const active = coins.filter(c => c.active);

The game uses map/filter/find constantly because a game does these same three things every frame: transform every item, keep the ones on screen, find the first match. Learning to read them fluently means you can read almost any game's data code.

When you have a choice

map vs filter vs find vs some

Choose the right one-liner by what you want back:

MethodReturnsUse when...
mapnew array (same length)you want each item transformed
filternew array (shorter)you want only the matching items
findone itemyou want the first match
somebooleanyou want "does any match?"
everybooleanyou want "do all match?"

arr.map(f)    // every item, changed
arr.filter(f) // only the items where f is true
arr.find(f)   // the first item where f is true
arr.some(f)   // true if f is true for any item
arr.every(f)  // true if f is true for every item

All of them take a question/transform function and all return new arrays (except some/every, which return booleans). None of them change the original, that immutability makes them safe and easy to reason about.

Examples

map: transform every item

map takes an array and returns a new array with each item changed. The thing it runs on each item is a small arrow function written as item => ....

const speeds = [340, 360, 420, 500];
const doubled = speeds.map(s => s * 2);
console.log(doubled);   // [680, 720, 840, 1000]

Read it out loud: "map over speeds; for each speed s, give me s 2." map *never changes the original array*: it returns a fresh one.

You can do richer transforms inside the function body:

const clamped = speeds.map(s => Math.min(720, s));   // cap each at 720

That s => ... is an **arrow function*: a short way to write a function you use once.

filter: keep what matches

filter returns a new array with only the items whose question-function returns true.

const obstacles = ["spike", "coin", "wall", "coin"];
const coins = obstacles.filter(o => o === "coin");
console.log(coins);     // ["coin", "coin"]

const fast = [340, 360, 420, 500, 720].filter(s => s > 400);
console.log(fast);      // [420, 500, 720]

Read it: "filter over obstacles; keep only the items o that equal 'coin'."

**Real game code*: this is exact code from app1/js/systems/SpawnController.js. Every frame it removes items that have scrolled off the left side:

recycle(cutoff) {
  this.ground = this.ground.filter(g => g.x + g.w > cutoff);
  this.hazards = this.hazards.filter(h => h.x + h.w > cutoff);
  this.coins = this.coins.filter(c => c.x + c.w > cutoff);
}

An item is still on screen if its right edge (g.x + g.w) is greater than the cutoff. The filtered result replaces the old list.

find: the first match

find returns the first item that answers "true", or undefined if none match. Unlike filter (an array), find returns a single item.

const obstacles = ["spike", "coin", "wall"];
const coin = obstacles.find(o => o === "coin");
console.log(coin);      // "coin"

**Real game code: find an unused* particle slot from app1/js/systems/Particles.js:

let p = this.particles.find(p => !p.active);

Translation: "find the first particle p that is not active." If none, p is undefined. That's how the game reuses recycled particles instead of always making new ones.

Two more helpers answer yes/no questions over a whole list, some (true if at least one matches) and every (true if all match).

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Objects
Previous Lesson
Objects
Next Lesson
State (State Machines)
State (State Machines) →