### Array.map

We all probably know `Array.map`

. It transforms an array of elements according to a given function.

```
double = (x) => x * 2;
map(double, [1, 2, 3]);
// [2, 4, 6]
```

I’ve always seen it implemented along these lines:

```
map = (fn, arr) => {
const mappedArr = [];
for (let i = 0; i < arr.length; i++) {
let mapped = fn(arr[i]);
mappedArr.push(mapped);
}
return mappedArr;
};
```

This video exposed me to an alternative `Array.map`

implementation. It’s from a 2014 JSConf — way before I jumped on the functional programming bandwagon.

**Edit:** David Cizek and Stephen Blackstone kindly pointed out edge-cases and suboptimal performance regarding this `map`

implementation. I wouldn’t advise anyone use this in a real app. My intention’s that we appreciate and learn from this thought-provoking, recursive approach. ?

The original example’s in CoffeeScript, here’s a JavaScript equivalent.

```
map = (fn, [head, ...tail]) =>
head === undefined ? [] : [fn(head), ...map(fn, tail)];
```

You might use David Cizek’s safer implementation instead.

```
map = (_fn_, [_head_, ..._tail_]) _=>_ (
head === undefined && tail.length < 1
? []
: [fn(head), ...map(fn, tail)]
);
```

Using ES6's destructuring assignment, we store the array’s first element into the variable `head`

. Then we store *all the other* array elements into `tail`

.

If `head`

is `undefined`

, that means we have an empty array, so just return an empty array. We’ve *mapped* nothing.

```
map(double, []);
// []
```

If `head`

*is not* `undefined`

we return a new array with `fn(head)`

as the first element. We’ve now *mapped* the array’s first element. Alongside it is `map(fn, tail)`

which calls `map`

again, this time with one less element.

Since `map`

returns an array, we use ES6’s spread syntax to concatenate it with `[head]`

.

Let’s step through this in the debugger. Paste this into your browser’s JavaScript console.

```
map = (fn, [head, ...tail]) => {
if (head === undefined) {
return [];
}
debugger;
return [fn(head), ...map(fn, tail)];
};
```

Now let’s `map(double, [1, 2, 3])`

.

We see our local variables:

```
head: 1
tail: [2, 3]
fn: double
```

We know `fn(head)`

is `2`

. That becomes the new array’s first element. Then we call `map`

again with `fn`

and the rest of the array’s elements: `tail`

.

So before the initial `map`

call even returns, we’ll keep calling `map`

until the array’s been emptied out. Once the array’s empty, `head`

will be `undefined`

, allowing our base case to run and finish the whole process.

On the next run, `head`

is `2`

and `tail`

is `[3]`

.

Since `tail`

isn’t empty yet, hit the next breakpoint to call `map`

again.

`head`

is `3`

, and `tail`

is an empty array. The next time this function runs, it’ll bail on line 3 and finally return the mapped array.

And here’s our end result:

### Array.filter

`Array.filter`

returns a new array based on the elements that satisfy a given predicate function.

```
isEven = (x) => x % 2 === 0;
filter(isEven, [1, 2, 3]);
// [2]
```

Consider this recursive solution:

```
filter = (pred, [head, ...tail]) =>
head === undefined
? []
: pred(head)
? [head, ...filter(pred, tail)]
: [...filter(pred, tail)];
```

If `map`

made sense, this'll be easy.

We’re still capturing the array’s first element in a variable called `head`

, and the rest in a separate array called `tail`

.

And with the same base case, if `head`

is `undefined`

, return an empty array and finish iterating.

But we have another conditional statement: only put `head`

in the new array if `pred(head)`

is `true`

, because `filter`

works by testing each element against a predicate function. Only when the predicate returns `true`

, do we add that element to the new array.

If `pred(head)`

doesn’t return `true`

, just call `filter(pred, tail)`

without `head`

.

Let’s quickly expand and step through this in the Chrome console.

```
filter = (pred, [head, ...tail]) => {
if (head === undefined) return [];
if (pred(head)) {
debugger;
return [head, ...filter(pred, tail)];
}
debugger;
return [...filter(pred, tail)];
};
```

And look for numbers ≤ 10:

filter(x => x <= 10,="" [1,="" 20]);<="" pre="">Since our array’s

`[1, 10, 20]`

,`head`

is the first element, 1, and`tail`

is an array of the rest:`[10, 20]`

.The predicate tests if

`x`

≤ 10, so`pred(1)`

returns`true`

. That’s why we paused on line 4’s`debugger`

statement.Since the current

`head`

passed the test, it’s allowed entry into our filtered array. But we’re not done, so we call`filter`

again with the same predicate, and now`tail`

.Move to the next

`debugger`

.We called

`filter`

with`[10, 20]`

so`head`

is now 10, and`tail`

is`[20]`

. So how does`tail`

get smaller with each successive iteration?We’re on line 4’s

`debugger`

once again because because 10 ≤ 10. Move to the next breakpoint.

`head`

's now 20 and`tail`

's empty.Since 20 > 10,

`pred(head)`

returns`false`

and our filtered array won’t include it. We’ll call`filter`

one more time without`head`

.This next time, however,

`filter`

will bail on line 2. Destructuring an empty array gives you`undefined`

variables. Continue past this breakpoint to get your return value.That looks correct to me!

## Array.reduce

Last but not least,

`Array.reduce`

is great for boiling an array down to a single value.Here’s my naive

`reduce`

implementation:`reduce = (fn, acc, arr) => { for (let i = 0; i < arr.length; i++) { acc = fn(acc, arr[i]); } return acc; };`

And we can use it like this:

`add = (x, y) => x + y; reduce(add, 0, [1, 2, 3]); // 6`

You’d get the same result with this recursive implementation:

`reduce = (fn, acc, [head, ...tail]) => head === undefined ? acc : reduce(fn, fn(acc, head), tail);`

I find this one much easier to read than recursive

`map`

and`filter`

.Let’s step through this in the browser console. Here’s an expanded version with

`debugger`

statements:`reduce = (fn, acc, [head, ...tail]) => { if (head === undefined) { debugger; return acc; } debugger; return reduce(fn, fn(acc, head), tail); };`

Then we’ll call this in the console:

`add = (x, y) => x + y; reduce(add, 0, [1, 2, 3]);`

## Round 1

We see our local variables:

`acc`

: our initial value of`0`

`fn`

: our`add`

function

`head`

: the array’s first element,`1`

`tail`

: the array’s other elements packed into aseparatearray,`[2, 3]`

Since

`head`

isn’t`undefined`

we’re going to recursively call`reduce`

,passing along its required parameters:

`fn`

: Obviously the`add`

function again ?

`acc`

: The result of calling`fn(acc, head)`

. Since`acc`

is`0`

, and`head`

is`1`

,`add(0, 1)`

returns`1`

.

`tail`

: The array’s leftover elements. By always using tail, we keep cutting the array down until nothing’s left!Move to the next

`debugger`

.## Round 2

Local variables:

`acc`

: Now it’s`1`

, because we called`reduce`

with`fn(acc, head)`

, which was`add(0, 1)`

at the time.

`fn`

: Still`add`

!

`head`

: Remember how we passed the previous`tail`

to`reduce`

? Now that’s been destructured, with`head`

representing its first element,`2`

.

`tail`

: There’s only one element left, so`3`

’s been packed into an array all by itself.We know the next

`reduce`

call will take a function, accumulator, and array. We can evaluate the next set of parametersusing the console.Expect these values on the next breakpoint.

## Round 3

Our local variables are as expected.

`head`

's first and only element is`3`

.And our array only has one element left,

`tail`

's empty! That means the next breakpoint will be our last.Let’s quickly evaluate our future local variables:

Move to the final breakpoint.

## Round 4

Check it out, we paused on line 3 instead of line 6 this time!

`head`

is`undefined`

so we’re returning the final,`6`

! It’ll pop out if you move to the next breakpoint.Looks good to me! Thank you so much for reading this.