Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python itertools—takewhile(): multiple predicates

Suppose a generator yields the below tuples one by one (from left to right)

(1, 2, 3), (2, 5, 6), (3, 7, 10), (4, 5, 11), (3, 5, 15), (4, 5, 9), (4, 6, 12)
...

and suppose I'd like to iterate as long as the predicate is true. Let that predicate be sum(yielded_value) < 20. Then the iterator will stop by (3, 5, 15). I can do it with, say:

list(itertools.takewhile(lambda x: sum(x) < 20, some_generator()))

Question, how do I write a similar expression with two predicates? Suppose I want:

list(itertools.takewhile(lambda x: sum(x) < 20 and first_value_of_tuple > 3, some_generator()))

(which, in this case, stop by (4, 6, 12).)

like image 619
blackened Avatar asked Dec 24 '22 11:12

blackened


2 Answers

You can access to elements of each tuple with index.

list(itertools.takewhile(lambda x: sum(x) < 20 and x[0] > 3, some_generator()))
like image 126
Ahsanul Haque Avatar answered Jan 08 '23 06:01

Ahsanul Haque


Since everything in itertools is lazily iterated, and you are using and for two predicates, you can simply use two takewhile iterators. Sometimes I find this more readable than putting both predicates in a single predicate function or lambda:

lessthan20 = itertools.takewhile(lambda x: sum(x) < 20, some_generator())
greaterthan3 = itertools.takewhile(lambda x: x[0] > 3, lessthan20)
list(greaterthan3)

It also makes it so that you don't have a single huge one liner if you need to add even more predicates in the future.

like image 23
eestrada Avatar answered Jan 08 '23 06:01

eestrada