Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally enumerating items in python

I'd like to enumerate those items in an iterable that satisfy a certain condition. I've tried something like

[(i,j) for i,j in enumerate(range(10)) if (3 < j) and (j < 8)]

(that tries to enumerate the numbers between 4 and 7 just for the sake of an example). From this, I get the result

[(4, 4), (5, 5), (6, 6), (7, 7)]

What I'd like to get is

[(0, 4), (1, 5), (2, 6), (3, 7)]

Is there a pythonic way to achieve the desired result?

Note that in the actual problem I'm working on, I don't know in advance how many items satisfy the condition.

like image 732
silvado Avatar asked May 21 '15 13:05

silvado


3 Answers

Do the enumerate last so the indexes start from 0.

enumerate(j for j in range(10) if (3 < j) and (j < 8))

If you need the list rather than enumerate object, just wrap this all in list()

like image 87
camz Avatar answered Sep 29 '22 11:09

camz


You can do the filtering in a generator, then do the enumeration on the result of that expression afterwards.

>>> [(index,value) for index,value in enumerate(j for j in range(10) if (3 < j) and (j < 8))]
[(0, 4), (1, 5), (2, 6), (3, 7)]

Or equivalently enumerate will yield tuples of (index, value) already so you can use

>>> list(enumerate(j for j in range(10) if (3 < j) and (j < 8)))
[(0, 4), (1, 5), (2, 6), (3, 7)]
like image 28
Cory Kramer Avatar answered Sep 29 '22 09:09

Cory Kramer


Why you are wrong: you get the result then filter it.

[(i,j) for i,j in enumerate(range(10))] will get [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)], then you use if (3 < j) and (j < 8)(j is the second item in the tuple), so the result would be [(4, 4), (5, 5), (6, 6), (7, 7)]

What you should do: filter the sequence passed to range() first.

it means: for example, you want to enumerate the numbers between 4 and 7, so you should do the filtering first

>>> [j for j in range(10) if 3 < j < 8]
[4, 5, 6, 7]

then you pass it to enumerate:

>>> list(enumerate([4, 5, 6, 7]))
[(0, 4), (1, 5), (2, 6), (3, 7)]

so, the solution should be:

>>> list(enumerate(i for in range(10) if 3 < i < 8))
[(0, 4), (1, 5), (2, 6), (3, 7)]

In a word, just remember to do the filtering first.

like image 26
lord63. j Avatar answered Sep 29 '22 10:09

lord63. j