Reputation: 21168
I want to write a method that would filter given list of objects depending on what operator or maybe function was provided to filter by.
Now my method looks like this:
def filter_by_names(objects, names, exclude=False):
if exclude:
return [obj for obj in objects if obj.name not in names]
else:
return [obj for obj in objects if obj.name in names]
Now it has two filter options, to return objects if its name is in provided names list or to do opposite: return objects whose name is not in provided names list.
What I want is to be able to dynamically specify how to filter. I though using operator
library, but it seems there is no not in
operator, so I would need to combine in
with not
which is a bit clunky.
I was thinking of using lambda like:
def filter_by_names(objects, names, fun=lambda obj, names: obj.name in names):
return [obj for obj in objects if fun(obj, names)]
This one works, but I was wondering maybe there is some better way to do something like that? With lambda I would always need to specify whole function even if I just only need different operator.
Upvotes: 2
Views: 2253
Reputation: 8510
how about using the xor operator, for example
>>> n = range(0,11,2)
>>> n
[0, 2, 4, 6, 8, 10]
>>> exclude = True
>>> [ x for x in range(10) if (x in n) ^ exclude ] # only the one that are not in n
[1, 3, 5, 7, 9]
>>> exclude = False
>>> [ x for x in range(10) if (x in n) ^ exclude ] # only the one that are also in n
[0, 2, 4, 6, 8]
>>>
this work because the xor of equals result in false and the xor of different result in true
Upvotes: 2
Reputation: 9597
def filter_by_names(objects, names, exclude=False):
return [obj for obj in objects if (obj.name in names) == (not exclude)]
Writing that with not exclude
(rather than (obj.name not in names) == exclude)
) allows you to pass an arbitrary truthy/falsy value for 'exclude', not just True or False.
Upvotes: 1
Reputation: 21168
For now I'm going with this approach. It is kind of limited, but it does what I currently need.
def filter_by_names(objects, names, exclude=False):
def _filter(names, name):
if exclude:
return name not in names
return name in names
return [obj for obj in objects if _filter(names, obj.name)]
P.S. I dropped operator
library, because using function which is limited either way, there is no need to have operator
lib.
Upvotes: 0
Reputation: 77850
Start with Python operators. contains
and not
should be enough to give you the desired control. However, this will be barely shorter than your current code, and the result is harder to read. On the other hand, this should give you plenty of lovely ideas on what you want to configure next.
Upvotes: 0