Codementor Events

Functional Mantra - Filter, Map, Reduce.

Published Jan 25, 2018
Functional Mantra - Filter, Map, Reduce.

In the world of coding, I find that some of my most enjoyable problems are decomposing arrays into new data structures — give me an array and tell me you need an object out of it, or give me an object and tell me you need two arrays out of it.

I find it such a fun problem to solve as elegantly as possible — using ONLY filter, map, and reduce. Okay, with the occasional Object.keys method as well, but that's just grease for the engine.

We have two arrays of objects and we wanna turn it into a nice juicy object.

The way I see it, we have two choices. Well, more, but we’re using functional coding.

We could either reduce or make an object placeholder and then map, but first, these are the two arrays.

const links = [ 
    {code: 'home'},
    {code: 'contact'} 
];

const subLinks = [ 
    {code: 'abc', parent: {code: 'home'} },
    {code: 'def', parent: {code: 'home'} },
    {code: 'xzy', parent: {code: 'contact'} }
];

This is the desired result.

const menu = { home: ['abc', 'def'], contact: ['xyz'] };

Basically, using the link, home or contact, we want to find the code snippet that goes with each of these. Then, we want to create a nicer looking object with our links as keys for the array of code snippets that go along with each link.

The first solution without reduce:

const menu = {};

links.map(link => {
   return menu[link.code] = subLinks
    	.filter(sl => sl.parent.code === link.code) 
        .map(sl => sl.code)       
});

What bothers me here is the use of the map without utilizing its returned array. We could just use a forEach for this, but tom8to tomato.

Also, the declared menu object would be great if we could have that created automagically inside the loop and just return an object.

Nevertheless, it does what it should do — filter on the parent code and return a smaller array from which we are only interested in the code value.

Bam! Simple and somewhat elegant — three lines of logic.

Now, onto the reduce example:

const menu = links.reduce((memo, menu) => { 
   memo[menu.code] = subLinks
    	.filter(sl => sl.parent.code === menu.code) 
    	.map(sl => sl.code); 
    return memo;
}, {});

To me, this feels more pure. We directly translate the array into a new data structure without mutating the original.

The code is readable, clear, and concise. It may be argued that it's a bit loopy, as in, we do quite a few loops through all of the arrays — giving us a O(n^2).

But I’m okay with this — if the input arrays end up being huge, then we can think about modifying them for a better big O result.

Discover and read more posts from Sten Muchow
get started
post commentsBe the first to share your opinion
Show more replies