Inverse of [].filter in JS?
JavascriptArraysFilterJavascript Problem Overview
I realize that I can do:
arr = arr.filter(function(n){ return !filterFunc(n); });
But is there any way to just invert a filter without wrapping the filterer in an anon function?
It just seems cumbersome.
Javascript Solutions
Solution 1 - Javascript
You can use an arrow function:
const a = someArr.filter(someFilter);
const a = someArr.filter(e => !someFilter(e));
Solution 2 - Javascript
Lodash provides a reject function that does the exact opposite of filter.
arr = _.reject(arr, filterFunc);
Solution 3 - Javascript
Take a look at lodash's negate function. It does exactly what @Yury Tarabanko mentions in his comment.
Usage:
arr = arr.filter(_.negate(filterFunc));
Solution 4 - Javascript
You can either add your own function or add a static/prototype methods to the Array object.
Code
Array Polyfill Methods
/**
* The not() method creates a new array with all elements that fail
* the test implemented by the provided function.
*
* Syntax
* arr.not(callback[, thisArg])
*
* @param callback
* Function to test each element of the array. Invoked with
* arguments (element, index, array). Return true to keep
* the element, false otherwise.
* @param thisArg
* Optional. Value to use as this when executing callback.
* @return Returns a new array containing all the items which fail
* the test.
*/
Array.prototype.not = function(callback) {
return this.filter(function () {
return !callback.apply(this, arguments);
});
};
/**
* Static method which calls Array.prototype.not on the array
* paramater.
*
* @see Array.prototype.not
*/
Array.not = function (array, callback) {
return array != null ? array.not(callback) : [];
};
Custom Function
function unfilter(array, callback) {
return array.filter(function () {
return !callback.apply(this, arguments);
});
}
This is safer to use than a polyfill, but it doesn't look as elegant in use.
unfilter(items, isFruit)
vs items.not(isFruit)
Example
// ================================================================
// Polyfill
// ================================================================
Array.prototype.not = function(callback) {
return this.filter(function () {
return !callback.apply(this, arguments);
});
};
// ================================================================
// Main
// ================================================================
var items = [{
name: 'Apple',
isFruit: true
}, {
name: 'Carrot',
isFruit: false
}, {
name: 'Melon',
isFruit: true
}, {
name: 'Potato',
isFruit: false
}];
var isFruit = function(item, index) {
return item != null && item.isFruit;
};
var getName = function(item, index) {
return item != null ? item.name : '?';
};
document.body.innerHTML = items.not(isFruit).map(getName).join(', ');
Solution 5 - Javascript
I wasn't happy with any of the answers directly, and actually wound up using newer JS features
arr.filter(() => ! filterfunc(...arguments));
This beats most of the others by not having to respecify the context (this
) at any point by using an arrow function and passing all parameters accordingly using the spread syntax on the arguments object.
It's also rather succinct, though I would rather an invert flag on the filter function, or a separate function.
The question might be a little on the old side, but it's still relevant.
Solution 6 - Javascript
filter
returns elements which return true
in your evaluation. If you want to inverse that, inverse your logic it within the function which tests each element.
Then, you could simply make this function work like so:
arr = arr.filter(filterFunc);
Solution 7 - Javascript
Lets take an example
var cars = [{
carname: "indica",
brand: "Tata"
},
{
carname: "accord",
brand: "Toyota"
},
{
carname: "vento",
brand: "volkswagen"
},
{
carname: "polo",
brand: "volkswagen"
},
{
carname: "Manza",
brand: "Tata"
},
{
carname: "Agile",
brand: "Chevrolet"
},
];
var isTata = function(car) {
return car.brand === "Tata"
}
var fiteredCars = cars.filter(isTata); // retuns objects of brand Tata
console.log(fiteredCars)
in reverse of this just change your logic
var isNotTata = function(car) {
return car.brand !== "Tata"
}
var dogs = cars.filter(isNotTata); // returns objects of brand other than Tata