Post

Filter and Map

In this post we’ll look at how to use the filter and map functions in JavaScript and why you would use them.

  1. Filter
  2. Advanced Filtering
  3. Map
  4. Using Filter & Map
  5. More Info

For the below examples, we’ll consider the situation were we have the following data about some people:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let data = [{
        name: 'Alex',
        age: 18,
        city: 'Melbourne'
    },{
        name: 'Chloe',
        age: 26,
        city: 'Perth'
    }, {
        name: 'Frank',
        age: 56,
        city: 'Brisbane'
    }, {
        name: 'Christine',
        age: 7,
        city: 'Darwin'
    }, {
        name: 'Craig',
        age: 17,
        city: 'Melbourne'
    }
];

This data represents the sort thing you would expect to deal with when handling API responses that use JSON, i.e. Arrays of Objects.


Filter

The filter function is called on an Array, takes a Function as input, and produces another Array as output. The input Function is called for every element in the input Array, and returns either true or false on whether it should be included in the output Array.

The Normal Way

Using the people data, we want an Array of all the people who are 18 or older. If you didn’t know about filter, you might do something like this:

1
2
3
4
5
6
7
let filteredData = [];

for (let i = 0; i < data.length; ++i) {
    if (data[i].age >= 18) {
        filteredData.push(data[i]);
    }
}

Using Filter

We can implement the same functionality with filter like this:

1
2
3
let filteredData = data.filter(function(person) {
    return person.age >= 18
});

This can be made even more concise using an Arrow Function:

1
let filteredData = data.filter(person => person.age >= 18);

Advanced Filtering

Intro

You aren’t limited to just filtering Arrays of Object. Any Array can be be filtered. Here is a sneaky trick you can do.

Recall that in JavaScript we can force values to be a boolean using the !! operator. This is performing the not operation twice, which cancels itself out. However, in the process, the first not operation converts it to a boolean, and the second not operation undoes the first, leaving us with the boolean value of the input.

1
2
3
4
5
6
7
8
9
!!true // true
!!null // false
!!NaN // false
!!undefined // false
!!''   // false
!![]   // true
!!{}   // true
!!0    // false
!!1    // true (any non-zero number will be true)

Why do I bring this up? Because we can use this trick remove these “false” values from Arrays with filter.

1
2
3
4
let data = [null, 0, 1, true, false, undefined];

let filteredData = data.filter(x => !!x);
// filteredData = [1, true]

Even better though, we don’t actually need the the !!. The filter function doesn’t require us to return true or false explicitly. The value we return will be forced to a boolean using something like !!.

1
2
3
let data = [null, 0, 1, true, false, undefined];

let filteredData = data.filter(x => x);

Use Case

Where else might this be useful? Removing empty strings from Arrays maybe:

1
2
3
4
5
6
7
8
let stringData = `
string1
string2
string3
`;

let data = stringData.split('\n');
// data = ["", "string1", "string2", "string3", ""]

We can remove those annoying empty strings with filter:

1
2
3
4
5
6
7
8
9
10
let stringData = `
string1
string2
string3
`;

let data = stringData.split('\n');

let filteredData = data.filter(x => x);
// filteredData = ["string1", "string2", "string3"]

We can even do it on the same line:

1
let data = stringData.split('\n').filter(x => x);


Map

The map function is called on an Array, takes a Function as input, and produces another Array as output. The input Function is called for every element in the input Array, and returns any value desired as the output. The output Array will be the same length as the input Array.

Normal Way

If we have an Array of numbers and wanted to calculate the square of each number, we could do something like this:

1
2
3
4
5
6
let inputNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let squaredNumbers = [];

for (let i = 0; i < inputNumbers.length; ++i) {
    squaredNumbers.push(Math.pow(inputNumbers[i], 2));
}

Using Map

We can implement the same functionality with map like this:

1
2
3
let squaredNumbers = inputNumbers.map(function(number) {
    return Math.pow(number, 2);
});

This can be made even more concise using an Arrow Function:

1
let squaredNumbers = inputNumbers.map(number => Math.pow(number, 2));

A Better Use Case

A much better use case is when working with Arrays of Object. Using the data at the start of this page, let’s see how we could get an Array of all the people’s names:

1
let names = data.map(person => person.name);

  • Yes, it’s that easy!


Using Filter & Map

We can combine filter and map to produce some short but powerful operations.

Using the people data again, let’s produce an Array of the names of people who are under 18:

1
let filteredData = data.filter(person => person.age < 18).map(person => person.name);

  • If speed is of concern, try and put the filter operation first to reduce the size of the Array passed to map.


More Info

More information regarding filter and map can be found here:

This post is licensed under CC BY 4.0 by the author.