## DEV Community is a community of 905,285 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

# Discussion on: How map() and reduce() Array method works in JavaScript.

For me the canonical way of learning about map and reduce is to

1. use recursion
2. implement `foldl` (reduce) using recursion
3. implement `map` in terms of `foldl`

Now in JavaScript this isn't terribly efficient …

``````const personArray = [
{ name: 'Swastik', age: 23 },
{ name: 'John', age: 42 },
{ name: 'Rock', age: 45 },
];

type Person = typeof personArray[number];

// reduce
function foldl<X, Y>(fn: (y: Y, x: X) => Y, to: Y, from: X[]): Y {
return from.length < 1 ? to : foldl(fn, fn(to, from[0]), from.slice(1));
}

function map<X, Y>(fn: (x: X) => Y, from: X[]): Y[] {
const append: (ys: Y[], x: X) => Y[] = (ys, x) => {
ys.push(fn(x));
return ys;
};
return foldl(append, [], from);
}

function rmap<X, Y>(fn: (x: X) => Y, from: X[]): Y[] {
// return from.length < 1 ?
//   [] :
//   [fn(from[0]), ...rmap(fn, from.slice(1))];
//
if (from.length < 1) return [];

const rest = rmap(fn, from.slice(1));
rest.unshift(fn(from[0]));
return rest;
}

function filter<X>(fn: (x: X) => boolean, from: X[]): X[] {
const appendAccept: (xs: X[], x: X) => X[] = (xs, x) => {
if (fn(x)) xs.push(x);
return xs;
};
return foldl(appendAccept, [], from);
}

function rfilter<X>(fn: (x: X) => boolean, from: X[]): X[] {
// return from.length < 1 ?
//   [] :
//   fn(from[0]) ?
//     [from[0], ...rfilter(fn, from.slice(1))] :
//     rfilter(fn, from.slice(1));
//
if (from.length < 1) return [];

const rest = rfilter(fn, from.slice(1));
if (fn(from[0])) rest.unshift(from[0]);
return rest;
}

type People = {
[name: string]: number;
};

const appendPerson: (a: People, p: Person) => People = (people, person) => {
people[person.name] = person.age;
return people;
};

console.log(foldl(appendPerson, {}, personArray));

const extractName: (p: Person) => string = (person) => person.name;

console.log(map(extractName, personArray));
console.log(rmap(extractName, personArray));

const inUpperAlphabet: (p: Person) => boolean = (person) =>
person.name[0].toLowerCase() > 'm';

console.log(filter(inUpperAlphabet, personArray));
console.log(rfilter(inUpperAlphabet, personArray));
``````

This transpiles down to

``````const personArray = [
{ name: 'Swastik', age: 23 },
{ name: 'John', age: 42 },
{ name: 'Rock', age: 45 },
];
// reduce
function foldl(fn, to, from) {
return from.length < 1 ? to : foldl(fn, fn(to, from[0]), from.slice(1));
}
function map(fn, from) {
const append = (ys, x) => {
ys.push(fn(x));
return ys;
};
return foldl(append, [], from);
}
function rmap(fn, from) {
if (from.length < 1) return [];
const rest = rmap(fn, from.slice(1));
rest.unshift(fn(from[0]));
return rest;
}
function filter(fn, from) {
const appendAccept = (xs, x) => {
if (fn(x)) xs.push(x);
return xs;
};
return foldl(appendAccept, [], from);
}
function rfilter(fn, from) {
if (from.length < 1) return [];
const rest = rfilter(fn, from.slice(1));
if (fn(from[0])) rest.unshift(from[0]);
return rest;
}
const appendPerson = (people, person) => {
people[person.name] = person.age;
return people;
};
console.log(foldl(appendPerson, {}, personArray));
const extractName = (person) => person.name;
console.log(map(extractName, personArray));
console.log(rmap(extractName, personArray));
const inUpperAlphabet = (person) => person.name[0].toLowerCase() > 'm';
console.log(filter(inUpperAlphabet, personArray));
console.log(rfilter(inUpperAlphabet, personArray));
``````