I was about to start writing this post and realized that this is a kind of post I have written before: How to represent a set of things with another set of things in code or math. For some reason I am fascinated by these reductions. Anyway, this post is a thought and code experiment where I try to implement different list transformations from functional programming using just one fundamental list transformation: reduce. If this makes no sense to you I should probably say that map, filter, find and reduce are different ways of transforming and operating on lists. The concepts are language agnostic, but for this post I will work with JavaScript where these methods are present on the array prototype 1. Therefore we do not have to implement these in JavaScript ourselves, but these concepts are extremely powerful and one might not realize it when first learning them. That is my experience at least. Doing this little experiment really helped me grasp the power of reduce and generally helps understanding all of the presented methods better. This is my goal:

  1. Assume that reduce is the only array method at our disposal
  2. Implement functions map, filter and find that simulate the work of the corresponding list operations

Below are my solutions making use of ES6 features called arrow functions and the spread operator. They probably do not follow the specification in all edge cases, but are more of a proof of concept. If you have suggestions for improvements, please let me know!

function map(arr, fn) {
	return arr.reduce((acc, item) => [...acc, fn(item)], [])
}

This one is pretty straight forward: We start off with an empty array as the initial value. With each iteration we concatenate this array with the transformed item using the spread operator.

function filter(arr, fn) {
	return arr.reduce((acc, item) => fn(item) ? [...acc, item] : acc, [])
}

Again, for filter we need to construct a new array and therefore pass an empty one as the initial value. During each iteration we either return the unchanged list or a copy with the current item pushed. The decision is made by the given function invoked with the current item.

function find(arr, fn) {
	return arr.reduce((acc, item) => fn(item) ? acc || item : acc, undefined)
}

(Thanks to juanmirod for spotting the missing undefined as initial value.)

Find is not a list transformation in the sense that it returns a new list. It returns a single item from the given list, but the operation can still be implemented as a reduce. Finding an item that matches is easy, we can just call the function with the current item during an iteration. But somehow we need to ensure that once we found an item, the result is not overwritten. The OR-operation ensures that if an earlier iteration has already returned a value we actually use that one. Note also that we do not pass any initial value and therefore acc will stay undefined as long as no item matches. This is how the real find operation on JavaScript arrays works.

I still think this implementation is a slightly imprecise, since searching for a falsy value like 0 will not return the last match instead of the first one. I don’t think it matters though. If you can construct a case where this returns the wrong thing I would be highly interested! Otherwise I am done with these for now. Again, this is just a thought experiment to see how powerful reduce is and not provide useful implementations of these list operations. I hope this helped you appreciate the power of reduce a little bit more!