Take the 2-minute tour ×

In Python, is there any counter available during the list comprehension as it would be in case of a for loop?

It would be more clear why I need a counter, with this example:

I wish to achieve the following:

Initial List: ['p', 'q', 'r', 's']

Desired List: [(1, 'P'), (2, 'Q'), (3, 'R'), (4, 'S')]

In the desired list, first element of every tuple are ordinal numbers. If it were just flat list, I could have used zip to achieve this. But however, the list I am dealing with is nested, three level deep (think of hierarchical data), and it is generated through list comprehension.

So, I was wondering is there any way to introduce those ordinal numbers during list comprehension. If not, what would be the best possible solution.

P.S. : Here the lower case letters are converted to uppercase, but that is not a part of problem, think of it as just a data conversion.


allObj = Category.objects.all()

tree =[(_, l1.name, [(__, l2.name, [(___, l3.name) for l3 in allObj if l3.parentid == l2.categoryid]) for l2 in allObj if l2.parentid == l1.categoryid]) for l1 in allObj if l1.parentid == None]

allObj contains data from table category, which in turn contains hierarchical data represented in the form of Adjacency List.

I have put _ where I need ordinal numbers to be. Notice that the list is nested, so there will be a separate counter at each level represented by 1, 2 & 3 _s.

share|improve this question
Have a look at enumerate(list, 1) docs.python.org/library/functions.html#enumerate –  Nobody Feb 8 '12 at 16:55
You can almost certainly achieve this using zip. No-one can tell you, if you don't show us your code. –  Marcin Feb 8 '12 at 16:55
@Marcin: I have added the code snippet as well. –  user1144616 Feb 8 '12 at 17:19
It is not trivial to count in this hierarchy saved in a flat list. You should at first build a real hierarchy and then you are able to count on each level. –  Nobody Feb 8 '12 at 17:28
@Nobody: This hierarchy comes from a database table as it is stored there in the form of Adjacency List. And what is building a real hierarchy, you mean trees? –  user1144616 Feb 8 '12 at 17:39
show 1 more comment

6 Answers

up vote 14 down vote accepted

The most basic case

[(i, x) for i, x in enumerate(some_list, 1)]

Apply a filter with an if-statements

[(i, x) for i, x in enumerate(some_list, 1) if i > 2]

or like this

[(i, x) for i, x in enumerate(some_list, 1) if x != 'p']

A word of advice

Most often you don't need to do this. Instead you just call enumerate(some_list, 1) where the enumeration is needed, in a for loop for example.

share|improve this answer
the trick would be incrementing the i. –  9000 Feb 8 '12 at 16:58
Nice one, I didn't know about the second argument in enumerate :) –  Samvel Feb 8 '12 at 16:59
9000: Now I don't follow you. According to your answer you know that it's done automaticly (if you did't comment before I added 1 as initial value which I forgot at first) –  Niclas Nilsson Feb 8 '12 at 17:01
samvel: Ok... :-) –  Niclas Nilsson Feb 8 '12 at 17:03
Maybe even better: list(enumerate(map(str.upper, oldList), 1)). Also note oldList to avoid the builtin name list. –  Nobody Feb 8 '12 at 17:05
show 3 more comments

As already showed in the other answers the standard library gives you enumerate, which means that you probably wont even need a list like:


because every time you need to bind the letter with a number related to its position you can just call enumerate.

>>> low = ['p', 'q', 'r', 's']
>>> upp = [c.upper() for c in low]
>>> for i,c in enumerate(upp, 1):
...     print(i,c)
1 P
2 Q
3 R
4 S

This was just an example, maybe you actually need to that kind of list.

share|improve this answer
+1 for this nice explanation. –  user1144616 Feb 8 '12 at 17:23
@user1144616: You're welcome! :) I just saw your updated question (with the code snippet). If you have to stick with that design I wish you all the luck, because it'll be hard to build and even more hard to read. If instead you can refactor your code, take a look at networkx, maybe it suites your case. –  Rik Poggi Feb 8 '12 at 18:57
add comment

RTFM: enumerate(['p', 'q', 'r', 's'], 1) gives you a generator yielding (1, 'p'), (2, 'q'), (3, 'r'), (4, 's'), convert it to list to taste.

share|improve this answer
I can use if to filter elements in case of List comprehension, how would that play here in case of enumerate(). –  user1144616 Feb 8 '12 at 17:33
Filter the incoming sequence, enumerate the result: enumerate((x for x in some_sequence if is_good(x)), 1) –  9000 Feb 8 '12 at 19:14
RTFM? He didn't mention enumerate in his original post, so how can he RTFM? –  Rabarberski Jan 20 at 10:37
@Rabarberski: He could read the fine manual to learn about enumerate and enjoy using it. If you think that the word "RTFM" is rude and condescending, I did not mean it, and such overtones are absent, if "The New Hacker Dictionary" (nee "Jargon File") is to be believed. –  9000 Jan 20 at 18:22
add comment
[(i + 1, x) for i, x in enumerate(L)]
share|improve this answer
add comment

Would something like this help?

i = 1

y = range(10)

s = [(i + y.index(x), x**2) for x in y]

print s

>>> [(1, 0), (2, 1), (3, 4), (4, 9), (5, 16), (6, 25), (7, 36), (8, 49), (9, 64), (10, 81)]

I have a suspicion that there may be a better way to do this than through comprehensions though.

share|improve this answer
add comment

I guess you want something like numbering all items, independent of the level of nesting. Maybe the following will help. Don't forget to create a new number for each list comprehension. next may be spelled __next__ in your version of Python.

>>> import itertools
>>> number = itertools.count().next
>>> [(number(), [(number(), x + 1) for x in range(y) if x % 2]) for y in range(10) if y % 3]
[(0, []), (1, [(2, 2)]), (3, [(4, 2), (5, 4)]), (6, [(7, 2), (8, 4)]), (9, [(10, 2), (11, 4), (12, 6)]), (13, [(14, 2), (15, 4), (16, 6), (17, 8)])]

Update: I know understand that you need different counters for each level of nesting. Just use more than one counter:

>>> number1 = itertools.count().__next__
>>> number2 = itertools.count().__next__
>>> print([(number1(), [(number2(), x + 1) for x in range(y) if x % 2]) for y in range(10) if y % 3])
[(0, []), (1, [(0, 2)]), (2, [(1, 2), (2, 4)]), (3, [(3, 2), (4, 4)]), (4, [(5, 2), (6, 4), (7, 6)]), (5, [(8, 2), (9, 4), (10, 6), (11, 8)])]

I.e., replace _ with number1() as defined above, __ with number2(), and so on. That's it.

share|improve this answer
add comment

Your Answer


