Map, Reduce, Filter - Better Explanations?

Does anyone else feel like an idiot every time they see a map, reduce, or filter function and completely not understand it? Well, I do!

I understand the concept and when they give you a simple example, but any time someone explains how they use it for anything more complicated, I can’t follow it.

When I was working on the Sorted Union algorithm challenge, they suggested using a reduce function. After fighting with it for a long time, I just resorted to a bunch of for loops.

If you have any really great sources for explaining it, please share!

Thanks!

Chris

4 Likes

Check out this playlist from mpjme: Functional programming in JavaScript

5 Likes

Do you, however, feel comfortable using these functions in simple examples? Maybe you just had not enough practice using them, so go, for example, to codewars and solve a bunch of simple problems.

But mpjme playlist is cool too, watch it)

1 Like

Looking reduce(): there is somewhere in the middle that says:

If you were to provide an initial value as the second argument to reduce, the result would look like this:

[0,1,2,3,4].reduce( (accumulator, currentValue, currentIndex, array) => {
  return accumulator + currentValue;
}, 10);

There is a diagram for reduce just below that. Think about it. Next, go checkout .map() .filter() and .reduce() exercises as they have some tests there to really drill it down for you.

Feel free to give us examples that you find too complicated, and we will figure this out with you.

Thanks for the tips everyone! I signed up for codewars and I think some practice over there will help a lot!

1 Like

One of the best things about codewars is that if you can’t figure it out using one of the methods (filter, reduce, etc) you can solve it with loops then look how others have solved it and learn from them…

1 Like

Yeah, that’s the habit I’m in. I just completed the Fibonacci Sum challenge, and forced myself to use a reduce function. Came out well!

Thanks for the codewars tip all! It was a big help!

In the end, the utilities methods for Arrays are not particularly complicated (and I don’t mean that with any condescension at all).

Just keep a few things in mind: they’re helper functions for performing common tasks. They usually iterate over every element in the array. Each utility method takes a callback function that is executed against each element in the array.

So, you’re essentially telling the array … look at each element and do this (the callback) with it.

What arguments the method passes into the callback function and what the method returns are how the utility methods vary. The name of the method is mean to convey useful information about what sort of operation is about to occur.

Array.forEach()
Iterate each element and execute the passed callback function. This method does not return a value/new array. Essentially, you’re simply saying I want to do something with each element, but nothing new will be returned. Basically the same as a for loop, except that you cannot break from .forEach() - it will always iterate all elements in the array.

Example: You have an array of customer objects, you need to update each object with some property value. Within forEach, you would directly modify the customer object with the new value.

customerList.forEach( function( customer ){
   customer.isGoodCustomer = true;
});

Array.map()
Iterate each element in the array - return a new array with an entry for each element in the original array. The callback function you provide should return a value for each element. This function allows you to translate (map) each element from its current value to a new value (as determined by your callback) in the returned array. If you return nothing from the callback function, the new array will have undefined for the new value (because a function always implicity returns undefined unless you specify a value to return).

Example: You have an array of customer objects, you want a list of customerIDs.

const customerIDs = customerList.map( function( customer ){ 
   return customer.id ;
});

Array.filter()
Iterate each element in the array - return a new array of filtered results. Your function should return a truthy or falsy value. If truthy, the element being dealt with in that iteration will be included in the returned array. If falsy, not.

Example: You have an array of customer objects, you want a list of those from a given state.

const state = 'CA';
const filteredCustomers = customerList.filter( function( customer ){
   return customer.shippingAddress.state === state;
});

Array.some()
Iterate each element in the array until you return a truthy value. Returns only true or false, not a new array. You supply a callback function that tests each element. This is useful for exiting iteration once any element matches a criteria set by your callback.

Example: Are some/any/at least one of these customers from California? (Not a great example, I know.)

const state = 'CA';
return customerList.some( function( customer ){
   return customer.shippingAddress.state === state;
});

Array.every()
Iterate each element in the array until you return a falsy value. Returns only true or false, not a new array. Like .some(), this is useful for finding out information about the array. In this case, whether or not all of them match the criteria defined by your callback.

Example:This could be useful in places like pre-post data validation.

const ok_to_process = customerList.every( function( customer ){
   // VALIDATION LOGIC
  return (customer.hasName && customer.hasAddress && customer.isReallyNice );
});

if ( !ok_to_process )
   return;

// CONTINUE PROCESSING
...

Array.reduce()
Iterate each element in the array - return one value for the entire array. Your callback determines how each element is handled. (This is the method I use least and always have to re-read the docs for).

Example: Find out how much a list of customers has spent, in total.

const totalPurchases = customerList.reduce( function( accumulated_value, customer ){
   return accumulated_value + customer.totalPurchases;
}, 0);

Reduce doesn’t have to be a mathematical operation. What if you wanted an object of states and an array of customers for each state?

let states = {};
states= customerList.reduce( function( states, customer ){

   const state = customer.shippingAddress.state;

   states[ state ] = states[ state ] || [];
   states[ state ].push( customer );
   return states;

}, states);

// NOW YOU SHOULD HAVE AN OBJECT WITH PROPERTY KEYS WHICH ARE STATES AND WHOSE
// VALUES ARE AN ARRAY OF CUSTOMERS WITH SHIPPING ADDRESSES FOR THOSE STATES
// YOU COULD ALSO JUST AS EASILY DO THIS WITH .forEach() ...

The fun thing is that, when you know what the utility functions return, you can start combining them in interesting ways.

Want a list of customerIDs for customers from California that purchased more that $100?

const orderThreshold = 100;
const state = 'CA';

const customerIDs = customerList.filter( function( customer ){
   return ( customer.shippingAddress.state === state && customer.totalOrders > orderThreshold );
})
.map( customer => customer.id );

// THE FILTER METHOD RETURNS AN ARRAY OF CUSTOMER OBJECTS THAT PASS THE FILTER FUNCTION
// THE MAP METHOD THEN TAKES THAT ARRAY AND RETURNS A NEW ARRAY OF CUSTOMER IDs

NOTE
All of the above examples can be done with for() loops. You don’t have to use any of the utility methods. But their use simplifies the reading of the code - when you see a .filter() method, you know that you will be getting a new array in return that matches some criteria. When you see a .map() method, you know you’ll get a new array with the same number of elements as the input array, but presumably with values that have been mapped/transformed in some fashion. When you see a `.reduce()’ method, you should expect the return value to be some form of summation/reduction of the data passed to it.

The utility methods are meant to simplify writing and assist the readability and reasoning about the code.

And that wound up a lot longer than I initially planned!

I hope it’s useful …

~Micheal

18 Likes

Way to go buddy. Seeing this reply really inspires me. It’s people like you who make this community awesome.

3 Likes

@imcodingideas Thanks a lot! I’m very happy I could be of some use.

thanks for bringing this to my attention… this guy is brilliant

I found this blog post very useful : https://danmartensen.svbtle.com/javascripts-map-reduce-and-filter
It explains basic usecase in an easy to understand way. Take a look!

1 Like

Why don’t you try to implement those methods yourself? I’d certainly help if you know how they work internally.

1 Like

If you don’t understand these concepts, stop what you are doing and sign up for https://watchandcode.com/courses/enrolled/premium.

It’ll teach you how to rebuild these methods using Test Driven Development. There is no better way to get more familiar with these concepts. I promise you it’ll be worth it. (No I’m not affiliated nor getting paid…I’m a fellow JS student).

If you are beginner, start with the free course: https://watchandcode.com/p/practical-javascript

1 Like

bookmarked!

I have been trying to get my head around these once and for all today since watching some of the the mpj vids this morning and have been struggling really when trying to practice it. I know what they do but putting into practice outside of the examples is a different matter - I will win sooner or later!

great post.

Thank you @michealhall

You’re welcome @markj78! I’m really glad I could help.

I enjoy MPJ’s videos as well. He’s definitely got an interesting personality and way about presenting things.

One thing I’ve done recently is join CodeWars … it’s a bit addictive (I have to watch out for that!), but many of the challenges I’ve done so far allow you to use Arrays/Array helper methods to great effect and it’s a good place to get used to working with them.

Definitely recommend it if you are not already on there.

In php a similr function would look like

Foreach ($bigBoxOfTacos as $taco) {
Echo var_dump($taco[‘taco_type’]);
}

diritos locosofhard

Js a map take and object or array. Goes through each item the does stuff.

//set vars
var bullymong = [ 'taco smasher', 'zorbug' ] 
//map to new array with sub arrays and properties.
var bullymong_names = map(bullymong, function(item){
Return [item, 'likes tacos'];
});

Functional techniques can help you write more declarative code that is easier to understand at a glance, refactor, and test. Most of the times it can be much easier to use the map , filter or reduce methods. Map operation takes a mapping function and a vector of data as arguments and returns a new vector, which is the result of applying the mapping function on each element of the vector independently. The filter function operates on a list and returns a subset of that list after applying the filtering rule. The reduce function will transform a given list into a single value by applying a given function continuously to all the elements.