Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python lambda list filtering with multiple conditions

My understanding about filtering lists with lambda is that the filter will return all the elements of the list that return True for the lambda function. In that case, for the following code,

inputlist = []
inputlist.append(["1", "2", "3", "a"])
inputlist.append(["4", "5", "6", "b"])
inputlist.append(["1", "2", "4", "c"])
inputlist.append(["4", "5", "7", "d"])

outputlist = filter(lambda x: (x[0] != "1" and x[1] != "2" and x[2] != "3"), inputlist)
for item in outputlist: print(item)

The output should be

['4', '5', '6', 'b']
['1', '2', '4', 'c']
['4', '5', '7', 'd']

But the output that I get is

['4', '5', '6', 'b']
['4', '5', '7', 'd']

I get the expected output, if I use

outputlist = filter(lambda x: (x[0] != "1" or x[1] != "2" or x[2] != "3"), inputlist)

What am I doing silly here? Or is my understanding not correct?

like image 228
user3300676 Avatar asked Jul 14 '16 06:07

user3300676


People also ask

How do you filter multiple conditions in Python?

Using Loc to Filter With Multiple ConditionsAdd each condition you want to be included in the filtered result and concatenate them with the & operator. You'll see our code sample will return a pd. dataframe of our filtered rows. Don't forget to include "import pandas as pd" at the top!

Can lambda take multiple arguments?

A lambda function can have as many arguments as you need to use, but the body must be one single expression.

Can Python lambda have multiple statements?

Lambda functions does not allow multiple statements, however, we can create two lambda functions and then call the other lambda function as a parameter to the first function.


2 Answers

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.

like image 182
shiva Avatar answered Nov 14 '22 21:11

shiva


['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]
like image 24
juanpa.arrivillaga Avatar answered Nov 14 '22 20:11

juanpa.arrivillaga