x = ['1', '2', '4', 'c'], so x[1]=='2', which makes the expression (x[0] != "1" and x[1] != "2" and x[2] != "3") be evaluated as False.
When conditions are joined by and, they return True only if all conditions are True, and if they are joined by or, they return True when the first among them is evaluated to be True.
x = ['1', '2', '4', 'c'], so x[1]=='2', which makes the expression (x[0] != "1" and x[1] != "2" and x[2] != "3") be evaluated as False.
When conditions are joined by and, they return True only if all conditions are True, and if they are joined by or, they return True when the first among them is evaluated to be True.
['1', '2', '4', 'c']
Fails for condition
x[0] != "1"
as well as
x[1] != "2"
Instead of using or, I believe the more natural and readable way is:
lambda x: (x[0], x[1], x[2]) != ('1','2','3')
Out of curiosity, I compared three methods of, er... comparing, and the results were as expected: slicing lists was the slowest, using tuples was faster, and using boolean operators was the fastest. More precisely, the three approaches compared were
list_slice_compare = lambda x: x[:3] != [1,2,3]
tuple_compare = lambda x: (x[0],x[1],x[2]) != (1,2,3)
bool_op_compare = lambda x: x[0]!= 1 or x[1] != 2 or x[2]!= 3
And the results, respectively:
In [30]: timeit.Timer(setup="import timeit,random; rand_list = [random.randint(1,9) for _ in range(4)]; list_slice_compare = lambda x: x[:3] != [1,2,3]", stmt="list_slice_compare(rand_list)").repeat()
Out[30]: [0.3207617177499742, 0.3230015148823213, 0.31987868894918847]
In [31]: timeit.Timer(setup="import timeit,random; rand_list = [random.randint(1,9) for _ in range(4)]; tuple_compare = lambda x: (x[0],x[1],x[2]) != (1,2,3)", stmt="tuple_compare(rand_list)").repeat()
Out[31]: [0.2399928924012329, 0.23692036176475995, 0.2369164465619633]
In [32]: timeit.Timer(setup="import timeit,random; rand_list = [random.randint(1,9) for _ in range(4)]; bool_op_compare = lambda x: x[0]!= 1 or x[1] != 2 or x[2]!= 3", stmt="bool_op_compare(rand_list)").repeat()
Out[32]: [0.144389363900018, 0.1452672728203197, 0.1431527621755322]
Filtering list of objects on multiple conditions
Multiple conditions in python filter function
python - How to filter list based on multiple conditions? - Stack Overflow
Applying multiple filters to a list.
Question is to find all the prime numbers between two given numbers.
i made a 'list' of numbers between the two given number(let the 2 numbers be 1 and 100).
then i did this
l1=list(filter(lambda x:x!=2 and x%2,l))
where l is my list with all numbers.
output i got [1,3,5,6.....99]
shouldn't my output be [1,2,3....99]
You can define a "filter-making function" that preprocesses the target list. The advantages of this are:
- Does minimal work by caching information about
target_listin a set: The total time isO(N_target_list) + O(N), since set lookups are O(1) on average. - Does not use global variables. Easily testable.
- Does not use nested for loops
def prefixes(target):
"""
>>> prefixes("FOLD/AAA.RST.TXT")
('FOLD', 'AAA', 'RST')
>>> prefixes("FOLD/AAA.RST.12345.TXT")
('FOLD', 'AAA', 'RST')
"""
x, rest = target.split('/')
y, z, *_ = rest.split('.')
return x, y, z
def matcher(target_list):
targets = set(prefixes(target) for target in target_list)
def is_target(t):
return prefixes(t) in targets
return is_target
Then, you could do:
>>> list(filter(matcher(target_list), mylist))
['FOLD/AAA.RST.12345.TXT', 'FOLD/AAA.RST.87589.TXT']
Define a function to filter values:
target_list = ["FOLD/AAA.RST.TXT"]
def keep(path):
template = get_template(path)
return template in target_list
def get_template(path):
front, numbers, ext = path.rsplit('.', 2)
template = '.'.join([front, ext])
return template
This uses str.rsplit which searches the string in reverse and splits it on the given character, . in this case. The parameter 2 means it only performs at most two splits. This gives us three parts, the front, the numbers, and the extension:
>>> 'FOLD/AAA.RST.12345.TXT'.rsplit('.', 2)
['FOLD/AAA.RST', '12345', 'TXT']
We assign these to front, numbers and ext.
We then build a string again using str.join
>>> '.'.join(['FOLD/AAA.RST', 'TXT']
'FOLD/AAA.RST.TXT'
So this is what get_template returns:
>>> get_template('FOLD/AAA.RST.12345.TXT')
'FOLD/AAA.RST.TXT'
We can use it like so:
mylist = [
"FOLD/AAA.RST.12345.TXT",
"FOLD/BBB.RST.12345.TXT",
"RUNS/AAA.FGT.12345.TXT",
"FOLD/AAA.RST.87589.TXT",
"RUNS/AAA.RST.11111.TXT"
]
from pprint import pprint
pprint(filter(keep, mylist))
Output:
['FOLD/AAA.RST.12345.TXT'
'FOLD/AAA.RST.87589.TXT']
Hi everyone,
Is there a function or any way to apply multiple filters to a list. Here's a concrete example: say we have two functions, f1 = lambda x: x%2 == 0 and f2 = lambda x: x>6. And we would like to apply these functions to L=[1,2,3,4,5,6,7,8,9,10]. The expected output should be [8,10].
Is there any class or method from functools or itertools to do this? Or just any design pattern to solve this?
I would simply make a function that returns the conditional:
def makeConditions(**p):
fieldname = {"ref": 0, "type": 1, "date": 2 }
def filterfunc(elt):
for k, v in p.items():
if elt[fieldname[k]] != v: # if one condition is not met: false
return False
return True
return filterfunc
Then you can use it that way:
>>> list(filter(makeConditions(ref=1), ex))
[[1, 'CB', '2017-12-11'], [1, 'CB', '2017-11-08']]
>>> list(filter(makeConditions(type='CB'), ex))
[[1, 'CB', '2017-12-11'], [2, 'CB', '2017-12-01'], [1, 'CB', '2017-11-08']]
>>> list(filter(makeConditions(type='CB', ref=2), ex))
[[2, 'CB', '2017-12-01']]
You was almost there, the idea is to create a list with the functions that checks the conditions you need, once you have them you can just call those functions over the list they have to check and use all function to check if all of them are evaluated to True, note the use of partial so the function in the filter call only takes the data list; check this:
from functools import partial
ex = [
# ["ref", "type", "date"]
[1, 'CB', '2017-12-11'],
[2, 'CB', '2017-12-01'],
[3, 'RET', '2017-11-08'],
[1, 'CB', '2017-11-08'],
[5, 'RET', '2017-10-10'],
]
conditions = {"ref": 3}
conditions2 = {"ref": 1, "type": "CB"}
def apply(data, *args):
"""
same as map, but takes some data and a variable list of functions instead
it will make all that functions evaluate over that data
"""
return map(lambda f: f(data), args)
def makeConditions(p, myList):
# For each key:value in the dictionnary
def checkvalue(index, val, lst):
return lst[index] == val
conds = []
for key, value in p.items():
if key == "ref":
conds.append(partial(checkvalue, 0, value))
elif key == "type":
conds.append(partial(checkvalue, 1, value))
elif key == "date":
conds.append(partial(checkvalue, 2, value))
return all(apply(myList, *conds)) # does all the value checks evaluate to true?
#use partial to bind the conditions to the makeConditions function
print(list(filter(partial(makeConditions, conditions), ex)))
#[[3, 'RET', '2017-11-08']]
print(list(filter(partial(makeConditions, conditions2), ex)))
#[[1, 'CB', '2017-12-11'], [1, 'CB', '2017-11-08']]
Here you have a live example
Do I have to execute the filter() function for each sublist or is it possible to do it for the whole global list?
Filter iterates over all the list aplying a function for each of the elements, if the function evaluates to True then the element will remind in the result, so filter works over the whole global list