You can see the part 1 here: https://medium.com/@ericholiveira/implementing-reduce-in-javascript-part-1-7ea8711e194

On last week we talked about reduce. We learned what it is, how to implement and finally how to use it to implement some other common functions.

This week we will learn how we can implement the function map, filter and flatMap using only the reduce function, and as a bonus we will see how we can serialize the execution of promises using it.

Implementing a function is the best way to learn how to use it, so lets skip to implementation :)

Map

Our map function receives two parameters, an array and a function. The result of it is a new array containing the result of the execution of the given function to each element of the given array.

Implementing it using only the reduce function:

const map = function(iterable,fn){

return reduce(iterable,(acc,n)=>acc.concat([fn(n)]),[])

}

console.log(map([1,2,3],i=>i+1)) //Prints [2,3,4]

This surely isn't the best implementation for the map function, i will be using it just to show how far we can go with reduce.

To implement the map function, we call the reduce function passing the given array, a functions and an empty array which will be used as the accumulator and will be returned by map.

The function passed as the second parameter of reduce, is really simple, it just accumulate in the new array the result of the mapping function (in our example i=>i+1) for each element of the given array.

Filter

The filter function also receive two parameters, the array, and a condition function. The result of it is a new array containing only the elements satisfying the given condition.

const filter = function(iterable,fn){

return reduce(iterable,(acc,n)=>fn(n)?acc.concat([n]):acc,[])

}

console.log(filter([1,2,3,4],i=>i<3)) // Prints [1,2]

As you can see the implementation is similar to that used on map, but now, the function passed to reduce, checks if the current element satisfies the given condition and if it is true, puts it in the result.

FlatMap

Look at the following code:

console.log(map([1,2],i=>[i,i+1])) //Prints [[1,2],[2,3]]

When we are using the map function, if the result of the passed function is also an array, the result will be an array of arrays. If what we want is to flat this to be a simple array of elements, we will use flatMap.

Putting it simple, flatMap, basically do the mapping and then flatten the result.

The implementation of it is also really simple:

const flatMap = function(iterable,fn){

return reduce(iterable,(acc,n)=>acc.concat(fn(n)),[])

}

console.log(flatMap([1,2],i=>[i,i+1]))//Prints [1,2,2,3]

The implementation is similar to map, the only change is that we do concat(fn(n)) instead of concat([fn(n)]) (on the map function), because in the first case, if the result of fn(n) is an array it will concatenate with the accumulator array keeping a flat structure.

Promises

For the last another really cool use of reduce is to use it to execute promises one after another and accumulate the result.

const sumPromises = function(promiseFunctions){

return reduce(promiseFunctions,async (accPromise,next)=>{

const accumulator = await accPromise

const currentResult = await next()

return accumulator + currentResult

},Promise.resolve(0))

}

const promiseFunctions = [

()=> Promise.resolve(1),

()=> Promise.resolve(2),

()=> Promise.resolve(3)

]



sumPromises(promiseFunctions).then(console.log)// Prints 6

Take your time to look at the code above.

The sumPromises functions receives an array of asynchronous functions, we use reduce over this array, passing also a async function, this async function waits for the last promise and stores the result in the accumulator constant, then waits for the next promise and stores the result in the currentResult constant, and finally returns the sum. Notice this is an async function so the return is a promise containing the sum. We start the accumulator of the reduce function with a promise containing the value 0.

Thats it, clap if you liked, and don’t forget to follow me here and on twitter https://twitter.com/Oliveira_Erich