JS Tip of the Day: Filter and Map With flatMap

Filter and Map With flatMap
Version: ES2019
Level: Intermediate

When you want to create a new array with the transformed values of another array, you can use Array’s map(). Unfortunately (sometimes) map() will always create a new array of the same size as the original. If you want to omit some of the mapped values, for example, you can use .filter(), but this will have to be called after map(), going through all of the values a second time, creating another new array.

You can get around this using flatMap(). flatMap() is another version of map() that also flattens the result by one level, combining the values of the arrays in the mapped array with the mapped array itself. If a mapped value were to return an empty array, that would be equivalent to filtering the value out.

let children = ['boy', 'girl', 'boy'];
let boyz2men = children.flatMap(child => {
    if (child === 'boy') {
        return 'man'; // mapped
    }
    return []; // filtered out
});
console.log(boyz2men); // ['man', 'man']

Given that mapped values can be arrays, and arrays can contain more than one value, you can also go beyond simple filtering (removing only) and instead also add values to the result making a mapped array that’s longer than the original.

let children = ['boy', 'girl', 'boy'];
let adults = children.flatMap(child => {
    if (child === 'boy') {
        return 'man';
    }
    return ['woman', 'mother-in-law']; // 2 for 1
});
console.log(adults); // ['man', 'woman', 'mother-in-law', 'man']

flatMap() only flattens the first level of arrays, or the equivalent of flat() with a depth set to 1. There is no way to have a greater depth with flatMap() alone. If you need to go deeper, you’ll want to call flat() separately after mapping normally.

More info: