Inverse of [].filter in JS?

JavascriptArraysFilter

Javascript 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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2958725View Question on Stackoverflow
Solution 1 - JavascriptapscienceView Answer on Stackoverflow
Solution 2 - JavascriptSascha KlattView Answer on Stackoverflow
Solution 3 - JavascriptsudeeView Answer on Stackoverflow
Solution 4 - JavascriptMr. PolywhirlView Answer on Stackoverflow
Solution 5 - JavascriptSEoFView Answer on Stackoverflow
Solution 6 - JavascriptJames LaiView Answer on Stackoverflow
Solution 7 - JavascriptWaghView Answer on Stackoverflow