Reputation: 17193
Is there a function in Python that does the opposite of filter
? I.e. keeps the items in the iterable that the callback returns False
for? Couldn't find anything.
Upvotes: 29
Views: 24722
Reputation: 334
I had the same situation, but I didn't wanted to have duplicated functions for my filter. This is my solution to filter the items of a dictionary and be able to invert the selection.
req_table = {
"ID_4001" : {"R_STAT":True, "V_STAT":False, "TYPE":"X", "VEL": 1},
"ID_0051" : {"R_STAT":True, "V_STAT":True, "TYPE":"X", "VEL": 23},
"ID_0741" : {"R_STAT":True, "V_STAT":False, "TYPE":"Y", "VEL": 32},
"ID_0701" : {"R_STAT":True, "V_STAT":False, "TYPE":"X", "VEL": 2353},
}
def count_prop(prop, with_val, rq_table, invert=False):
return len(list(filter(lambda tc : (tc[1][prop] == with_val)^invert, rq_table.items())))
print("Items of type X: {}".format(count_prop("TYPE", "X", req_table)))
print("Items of type Y: {}".format(count_prop("TYPE", "X", req_table, invert=True)))
The trick is the ^
which acts as a enabled not
.
Upvotes: 0
Reputation: 1899
From Ross Bencina's comment to Martijn Pieters's answer:
Your reasoning is not very convincing. The first case can already be written
positive = filter(some_test, values)
therefore what is asked for should be at least as simple as
negative = filter(not(some_test), values)
I would suggest using a simple negating wrapper function:
def _not(func):
def not_func(*args, **kwargs):
return not func(*args, **kwargs)
return not_func
which allows to write the second line as above (with the added underscore or other distinction, since the not
operator cannot and probably should not be overwritten):
negative = filter(_not(some_test), values)
Upvotes: 6
Reputation: 4173
Another option:
from operator import not_
compose = lambda f, g: lambda x: f( g(x) )
...
ys = filter(compose(not_, predicate), values)
You may have a pre-rolled version of compose()
available (e.g. in functional or toolz).
Upvotes: 9
Reputation: 2244
You can do this with itertools.filterfalse
or as Martijn suggests, put a not
somewhere inside the lambda you use in your filter.
Upvotes: 25
Reputation: 1122252
No, there is no built-in inverse function for filter()
, because you could simply invert the test. Just add not
:
positive = filter(lambda v: some_test(v), values)
negative = filter(lambda v: not some_test(v), values)
The itertools
module does have itertools.ifilterfalse()
, which is rather redundant because inverting a boolean test is so simple. The itertools
version always operates as a generator.
Upvotes: 42