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.
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 tomap
.
More Info
More information regarding filter
and map
can be found here: