Array Map, Filter and Reduce in JS

John Ferris

Lately, I’ve been working on an exciting data visualization project for one of our clients. This requires a lot of data manipulation as data is pulled from the API server and transformed into visualizations. I found myself using the same array methods over and over to get this work done–Map, Filter and Reduce.

Map, Filter, and Reduce are used to take an array of things and turn them into something else. Here’s how I like to look at them.


An array of fruit mapped to fruit slices.

Map

You have an array of items and want to transform each of them. The result is a new array of the exact same length containing the manipulated items.


An array of fruit filtered down to just oranges.

Filter

You have an array and want to filter out certain items. The result is a new array with the same items, but with some excluded. The length of the new array will be the same (if no values were omitted) or shorter than the original.


An array of fruit reduced to fruit salad.

Reduce

You have an array of items and you want to compute some new value by iterating over each item. The result can be anything, another array, a new object, a boolean value etc.


Map, Filter, and Reduce do not manipulate the original array. In each case, you end up with a brand new value. Let’s look at some examples.

Array.map()

Let’s say we have an array of objects representing various Transformers (The 1980’s G1 Transformers, not that terrible Michael Bay junk.)

var transformers = [
  {
    name: 'Optimus Prime',
    form: 'Freightliner Truck',
    team: 'Autobot'
  },
  {
    name: 'Megatron',
    form: 'Gun',
    team: 'Decepticon'
  },
  {
    name: 'Bumblebee',
    form: 'VW Beetle',
    team: 'Autobot'
  },
  {
    name: 'Soundwave',
    form: 'Walkman',
    team: 'Decepticon'
  }
];

We want a new array that lists all the forms that our robots take on. Array.map() makes this easy.

The basic signature looks like this:

Array.prototype.map(callback(item));

In most cases, the above will do. In more complex scenarios, the full signature looks like this:

Array.prototype.map(callback(item[, index], array])[, thisArg]);

The callback is run on each item of the array. Its return value will be the new item in the resulting array. We can write this a few different ways:

As a named function:

function getForm(transformer) {
  return transformer.form;
}
var robotsInDisguise = transformers.map(getForm);
/** robosInDisguise === ['Freightliner Truck', 'Gun', 'VW Beetle', 'Walkman'] */

As an anonymous function:

robotsInDisguise = transformers.map(function(transformer) {
  return transformer.form;
});

As an arrow function:

robotsInDisguise = transformers.map(transformer => transformer.form);

The above ES2015 arrow function syntax is super handy for quick maps where you just want to pull a simple computed value out of each item of an array.

Array.filter()

Array.filter allows us to take an array of items and filter it down to just the items we want.

The full function signature is

Array.prototype.filter(callback(item));

The callback takes the item as an argument and returns a boolean value. If it returns true, the item is added to the new array. If it returns false, the item is left out.

Let’s filter our list of Transformers down to just Autobots.

function isAutobot(transformer) {
  return transformer.team === ‘Autobot’;
}
 
var autobots = transformers.filter(isAutobot);
/**
autobots ==  [
  {
    name: 'Optimus Prime',
    form: 'Freightliner Truck',
    team: 'Autobot'
  },
  {
    name: 'Bumblebee',
    form: 'VW Beetle',
    team: 'Autobot'
  }
]
*/

Array.reduce()

Array.reduce() allows you to compute a single value by iterating over a list of items. Reduce is the trickiest of the three array methods we’ve looked at as the signature is a bit more complex.

Array.prototype.reduce(callback(previousValue, currentValue[, index], array]), initialValue)

Just remember, we have an array of items and want to reduce them to a single value. Let’s say we have an array of Construction Transformers. Constructicons are construction robots that combine, Voltron style, into a giant robot called Devastator. Let’s code that for pretend.

var constructicons = [
  {
    name: 'Scrapper',
    form: 'Freightliner Truck',
    team: 'Decepticon',
    bodyPart: 'rightLeg'
  },
  {
    name: 'Hook',
    form: 'Mobile Crane',
    team: 'Decepticon',
    bodyPart: 'upperTorso'
  },
  {
    name: 'Bonecrusher',
    form: 'Bulldozer',
    team: 'Decepticon',
    bodyPart: 'leftArm'
  },
  {
    name: 'Scavenger',
    form: 'Excavator',
    team: 'Decepticon',
    bodyPart: 'rightArm'
  },
  {
    name: 'Mixmaster',
    form: 'Concrete Mixer',
    team: 'Decepticon',
    bodyPart: 'leftLeg'
  },
  {
    name: 'Long Haul',
    form: 'Dump Truck',
    team: 'Decepticon',
    bodyPart: 'lowerTorso'
  }
];

The reduce callback takes at least two arguments. The first is the previous value returned from the last iteration. The second is the current value being iterated over in the array. The return value gets passed on as the 1st argument in the next iteration. The return value of the initial reduce call will be the return value from the callback on the final iteration.

function assemble(combiner, transformer) {
  // On each iteration, add the current transformer to the form object of the combiner.
  combiner.form[transformer.bodyPart] = transformer.name;
  return combiner;
}
Constructicons assemble into Devastator

When we call reduce on the array; the first argument is the callback; the second is the initial value passed that callback on the first iteration. In the below example begin with a new Transformer with just the name and team values set. On each iteration of assemble, we add a Constructicon to the form property, until it is fully assembled.

var devastator = constructicons.reduce(assemble, {
  name: ‘Devastator’,
  team: ‘Decepticon’,
  form: {}
});
 
/**
devastator == {
  name: ‘Devastator’,
  team: ‘Decepticon’,
  form: {
    leftArm: "Bonecrusher"
    leftLeg: "Mixmaster"
    lowerTorso: "Long Haul"
    rightArm: "Scavenger"
    rightLeg: "Scrapper"
    upperTorso: "Hook"
  }
}
*/

These basic methods can be super powerful when combined together. This is just small sample of the methods I find myself using often. Checkout MDN's great documentation for more!


About the Author

John has been working in the print and interactive design industry since 2000. In addition to leading the front-end engineering team at Aten, John has spoken at many industry conferences throughout the U.S and internationally, including CSS Dev Conference and DrupalCons Portland, Austin, Amsterdam and L.A., on topics ranging from SVG to CSS architecture and layout design patterns. He is...

Read More