How to filter an array of objects based on a secondary array in JavaScript
By Mike Street
Was recently asked to help write some code for this scenario - just jotting it down in case I need it again!
The Input
There is an array of objects with details of a football game. Each player that played in the match is associated with an ID and tracked on the game object:
const games = [
{
id: '1',
players: [1, 2, 4, 5]
}, {
id: '2',
players: [3, 5, 6]
}, {
id: '3',
players: [1, 2, 4]
}
];
We then wish to filter this array, by extracting the games that either of the following players played in:
The filter
const playersToFilter = [3, 5];
With the code, we should get an array with games 1
and 2
in - as players 3
and 5
played in one or both of them:
Expected output
[{
id: '1',
players: [1, 2, 4, 5]
}, {
id: '2',
players: [3, 5, 6]
}]
The result
Filtering the array took some time to get to the result, but once figured out it turned out to be 3 lines of code (when written in ES2015).
ES2015
const filteredGames = games.filter(game => {
return game.players.some(player => playersToFilter.includes(player));
});
Before I jump in explaining what each line/function does - I'll also include the code in "old money" (still using the functions) but without the =>
shortcutes
var filteredGames = games.filter(function(game) {
return game.players.some(function(player) {
return playersToFilter.includes(player)
})
});
The explanation
const filteredGames = games.filter()
The filter function enables you to quickly trim down an array by using a conditional statement and returning true
or false
. It loops through all of the items of the given array (in this case, games
), calculates the result and populates the variable based on the outcome. If the function returns true, the whole item (for example, the game with the ID and players) gets added to a new array.
As an example, say you wanted all numbers lower than 3
from an array. You could use filter()
like so:
let numbers = [1, 2, 3, 4];
let lowNumbers = numbers.filter(n => n < 3);
lowNumbers
would now equal [1, 2]
. Pre ES2015, this code would look something like:
var numbers = [1, 2, 3, 4];
var lowNumbers = [];
for (i = 0; i < numbers.length; i++) {
if(numbers[i] < 3) {
lowNumbers.push(numbers[i]);
}
}
You can already see that the filter
function allows for more succinct code.
return game.players.some();
Remembering that, within the filter
function, we are "looping" through the objects, we now have the properties available to us. game.players
will return the array of players.
The some()
function is really the magic ingredient here. It allows you to test an array to see if any of the items match the conditions you're passing in. Once again, it loops through each element (in this instance player
). You can read more about the some
function on MDN.
Without the some()
function, we would need to loop through the players, setting a variable to true
if the condition exists and then passing that variable back at the end.
playersToFilter.includes(player)
This is the condition we are passing to the some()
function. It is a check to see if the playersToFilter
array includes the current player
we are looping through.
If this returns true
to the some()
filter, it would mean this line would return true
:
return game.players.some(player => playersToFilter.includes(player));
With that line returning true
, this would in turn pass true
to the filter()
function, which would include it in the new array.
Still not making sense? Feel free to drop a comment below or tweet me with your questions!