I have an array, and I want to filter it to only include items which match a certain condition. Can this be done in JavaScript?
Some examples:
[1, 2,
A more concise answer following the one from @Scimonster, using ES6 syntax, would be:
// even numbers
const even = [1, 2, 3, 4, 5, 6, 7, 8].filter(n => n%2 == 0);
// words with 2 or fewer letters
const words = ["This", "is", "an", "array", "with", "several", "strings", "making", "up", "a", "sentence."].filter(el => el.length <= 2);
// truable elements
const trues = [true, false, 4, 0, "abc", "", "0"].filter(v => v);
console.log(even);
console.log(words);
console.log(trues);
For this, you can use the Array#filter() method, introduced in ECMAScript5. It is supported in all browsers, except for IE8 and lower, and ancient versions of Firefox. If, for whatever reason, you need to support those browsers, you can use a polyfill for the method.
filter()
takes a function as its first argument. For every item of the array, your function is passed three arguments - the value of the current item, its index in the array, and the array itself. If your function returns true
(or a truthy value, e.g. 1
, "pizza"
, or 42
), that item will be included in the result. Otherwise, it won't. filter()
returns a new array - your original array will be left unmodified. That means that you'll need to save the value somewhere, or it'll be lost.
Now, in the examples from the question:
var myNumbersArray = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(myNumbersArray.filter(function(num){
return !(num % 2); // keep numbers divisible by 2
}));
console.log(myNumbersArray); // see - it hasn't changed!
var myStringArray = ["This", "is", "an", "array", "with", "several", "strings", "making", "up", "a", "sentence."];
console.log(myStringArray.filter(function(str){
return str.length < 3; // keep strings with length < 3
}));
console.log(myStringArray);
var myBoolArray = [true, false, 4, 0, "abc", "", "0"];
console.log(myBoolArray.filter(Boolean));
// wow, look at that trick!
console.log(myBoolArray);
And for completeness, an example that also uses the index and array parameters: Removing duplicates from the array:
var myArray = [1,1,2,3,4,5,6,1,2,8,2,5,2,52,48,123,43,52];
console.log(myArray.filter(function(value, index, array) {
return array.indexOf(value) === index;
}));
To filter entries which aren't strictly arrays, and thus don't have the .filter
property on their prototype, but are still iterable (like document.getElementsByTagName
), you can use
Array.prototype.filter.call(collection, function filterFunction(el, index, collection) {
...
});
Or the shorthand
[].filter.call(collection, function filterFunction(el, index, collection) {
...
});
As for objects which are not iterable, but you still want to filter properties and get an array of keys that pass filtering, you can combine with Object.keys
like so:
var obj = { one: 1, two: 2, three: 3, four: 4 };
var filtered = Object.keys(obj).filter(function(key) {
return obj[key] % 2 === 0;
}); //filtered == ['two', 'four']
Then, you can create a new object containing those properties:
var filteredObj = filtered.reduce(function(newObj, currentKey) {
newObj[currentKey] = obj[currentKey]; //Add the original value to the new object
return newObj; //Return the new object to continue iteration
}, {}) // Begin iteration with a blank object
//filteredObj is now { two: 2, four: 4 }
The above can even be combined into a function!
function filterObject(obj, testCallback) {
return Object.keys(obj).filter(function(key, index, array) {
return testCallback(obj[key], index, array); //Call original filter but pass the property
}).reduce(function(newObj, currentKey) {
newObj[currentKey] = obj[currentKey]; //Add the original value to the new object
return newObj; //Return the new object to continue iteration
}, {}); // Begin iteration with a blank object
}
And use like this:
var obj = { one: 1, two: 2, three: 3, four: 4 };
var filteredObj = filterObject(obj, function(el) { return el % 2 === 0 });