Accessing the index in 'for' loops?

Created 06.02.2009 22:47
Viewed 2.49M times
4094 votes

How do I access the index in a for loop like the following?

ints = [8, 23, 45, 12, 78]
for i in ints:
    print('item #{} = {}'.format(???, i))

I want to get this output:

item #1 = 8
item #2 = 23
item #3 = 45
item #4 = 12
item #5 = 78

When I loop through it using a for loop, how do I access the loop index, from 1 to 5 in this case?

3
Comments
Note that indexes in python start from 0, so the indexes for your example list are 0 to 4 not 1 to 5 by plugwash, 02.10.2018 16:54
@JoanVenge this is a great question I've had MANY TIMES. And the comment above is saying it's zero-indexed-based (so, we humans count 1 to 3 as 1,2,3, but computers count as 0,1,2 (so, a size of 3 e.g is [0,1,2] (0 counts as 1)) And, this questions answers below are also, Brilliant. Thanks for this! by William Martens, 23.03.2021 12:42
@WilliamMartens happy to help :) by Joan Venge, 23.03.2021 14:13
Answers 22
5
6910

Using an additional state variable, such as an index variable (which you would normally use in languages such as C or PHP), is considered non-pythonic.

The better option is to use the built-in function enumerate(), available in both Python 2 and 3:

for idx, val in enumerate(ints):
    print(idx, val)

Check out PEP 279 for more.

06.02.2009 22:52
Comments
As Aaron points out below, use start=1 if you want to get 1-5 instead of 0-4. by clozach, 31.03.2018 22:16
Does enumerate not incur another overhead? by TheRealChx101, 17.10.2019 23:03
@TheRealChx101 according to my tests (Python 3.6.3) the difference is negligible and sometimes even in favour of enumerate. by Błotosmętek, 07.02.2020 12:18
@TheRealChx101: It's lower than the overhead of looping over a range and indexing each time, and lower than manually tracking and updating the index separately. enumerate with unpacking is heavily optimized (if the tuples are unpacked to names as in the provided example, it reuses the same tuple each loop to avoid even the cost of freelist lookup, it has an optimized code path for when the index fits in ssize_t that performs cheap in-register math, bypassing Python level math operations, and it avoids indexing the list at the Python level, which is more expensive than you'd think). by ShadowRanger, 06.10.2020 18:19
@MikeHordecki This is just a ## Brilliant Answer! Thanks for this! Question is 12+years old and this answer is working flawlessly. by William Martens, 12.03.2021 09:39
4
899

Using a for loop, how do I access the loop index, from 1 to 5 in this case?

Use enumerate to get the index with the element as you iterate:

for index, item in enumerate(items):
    print(index, item)

And note that Python's indexes start at zero, so you would get 0 to 4 with the above. If you want the count, 1 to 5, do this:

for count, item in enumerate(items, start=1):
    print(count, item)

Unidiomatic control flow

What you are asking for is the Pythonic equivalent of the following, which is the algorithm most programmers of lower-level languages would use:

index = 0            # Python's indexing starts at zero
for item in items:   # Python's for loops are a "for each" loop 
    print(index, item)
    index += 1

Or in languages that do not have a for-each loop:

index = 0
while index < len(items):
    print(index, items[index])
    index += 1

or sometimes more commonly (but unidiomatically) found in Python:

for index in range(len(items)):
    print(index, items[index])

Use the Enumerate Function

Python's enumerate function reduces the visual clutter by hiding the accounting for the indexes, and encapsulating the iterable into another iterable (an enumerate object) that yields a two-item tuple of the index and the item that the original iterable would provide. That looks like this:

for index, item in enumerate(items, start=0):   # default is zero
    print(index, item)

This code sample is fairly well the canonical example of the difference between code that is idiomatic of Python and code that is not. Idiomatic code is sophisticated (but not complicated) Python, written in the way that it was intended to be used. Idiomatic code is expected by the designers of the language, which means that usually this code is not just more readable, but also more efficient.

Getting a count

Even if you don't need indexes as you go, but you need a count of the iterations (sometimes desirable) you can start with 1 and the final number will be your count.

for count, item in enumerate(items, start=1):   # default is zero
    print(item)

print('there were {0} items printed'.format(count))

The count seems to be more what you intend to ask for (as opposed to index) when you said you wanted from 1 to 5.


Breaking it down - a step by step explanation

To break these examples down, say we have a list of items that we want to iterate over with an index:

items = ['a', 'b', 'c', 'd', 'e']

Now we pass this iterable to enumerate, creating an enumerate object:

enumerate_object = enumerate(items) # the enumerate object

We can pull the first item out of this iterable that we would get in a loop with the next function:

iteration = next(enumerate_object) # first iteration from enumerate
print(iteration)

And we see we get a tuple of 0, the first index, and 'a', the first item:

(0, 'a')

we can use what is referred to as "sequence unpacking" to extract the elements from this two-tuple:

index, item = iteration
#   0,  'a' = (0, 'a') # essentially this.

and when we inspect index, we find it refers to the first index, 0, and item refers to the first item, 'a'.

>>> print(index)
0
>>> print(item)
a

Conclusion

  • Python indexes start at zero
  • To get these indexes from an iterable as you iterate over it, use the enumerate function
  • Using enumerate in the idiomatic way (along with tuple unpacking) creates code that is more readable and maintainable:

So do this:

for index, item in enumerate(items, start=0):   # Python indexes start at zero
    print(index, item)
21.01.2015 17:11
Comments
Does the "Getting a count" example work when items is empty? by Bergi, 22.02.2020 15:36
I am sending data using ajax to Django views as an array in the form of two values in a variable legData with values as [1406, 1409]. If I print to the console using print(legData), the output is [1406,1409]. However, if I try to parse the individual values of the list like for idx, xLeg in enumerate(legData): print(idx, xLeg), it gets me an output of individual integers such as [, 1, 4, 0, 6, and so on against the indices 0, 1, 2, 3, 4 etc. (yes, the square brackets & comma are also being output as if they were part of the data itself). What is going wrong here? by user12379095, 15.05.2020 15:51
@user12379095 you probably have the data in the wrong type (a string) and you need to convert it to an actual list of numbers instead of a string. That is somewhat off topic here, please delete your comment and flag mine to be deleted as no longer needed when you see this. by Aaron Hall, 15.05.2020 23:01
@Bergi: It won't, but you can just add count = 0 before the loop to ensure it has a value (and it's the correct one when the loop never assigns to count, since by definition there were no items). by ShadowRanger, 06.10.2020 18:21
4
176

It's pretty simple to start it from 1 other than 0:

for index, item in enumerate(iterable, start=1):
   print index, item  # Used to print in python<3.x
   print(index, item) # Mirate print() after 3.x+
   
27.05.2014 10:04
Comments
The question was about list indexes; since they start from 0 there is little point in starting from other number since the indexes would be wrong (yes, the OP said it wrong in the question as well). Otherwise, calling the variable that is tuple of index, item just index is very misleading, as you noted. Just use for index, item in enumerate(ints). by Antti Haapala, 18.03.2016 09:18
Better is to enclose index inside parenthesis pairs as (index), it will work on both the Python versions 2 and 3. by hygull, 02.01.2018 11:31
@AnttiHaapala The reason, I presume, is that the question's expected output starts at index 1 instead 0 by pushkin, 30.11.2018 18:24
@hygull: Turning index into (index) won't change a thing on either Py2 or Py3. I feel like maybe you're thinking of the change to print; the only way to make that work on both Py2 and Py3 is to add from __future__ import print_function to the top of your file to get consistent Py3-style print, and change the print to print(index, item). Or you read an earlier edit of the question when index was the original tuple, not unpacked to two names, but the parentheses still don't change anything if you fail to unpack. by ShadowRanger, 06.10.2020 18:23
8
98
for i in range(len(ints)):
   print(i, ints[i]) # print updated to print() in Python 3.x+ 
06.02.2009 22:49
Comments
That should probably be xrange for pre-3.0. by Ben Blank, 06.02.2009 22:52
Use enumerate instead by saulspatz, 01.08.2015 21:28
For Python 2.3 above, use enumerate built-in function since it is more Pythonic. by januarvs, 15.03.2017 06:31
Enumerate is not always better - it depends on the requirements of the application. In my current situation the relationships between the object lengths is meaningful to my application. Although I started out using enumerate, I switched to this approach to avoid having to write logic to select which object to enumerate. by adg, 31.03.2017 23:18
@adg I don't see how avoid enumerate saves any logic; you still have to select which object to index with i, no? by chepner, 15.09.2017 23:15
@chepner If one is iterating through multiple lists, using range may make sense. Though zip is probably more Pythonic for these cases, so using range would still be a premature optimization, as other comments mention. by Graham, 23.12.2018 16:33
This representation is useful when I use numba or cython. by naoki fujita, 07.05.2019 15:36
@Graham: Using range would be a premature pessimization, as zip (itertools.izip on Py2) is strictly better for that case. About the only use case for range I know of where there isn't a better alternative is iterating over overlapping slices of a sequence (where you need the index, but then use it to slice, so getting a value with the index isn't helpful). You could make it work without range (and for non-sequences) with itertools.tee, but it's ugly. by ShadowRanger, 06.10.2020 18:27
Show remaining 3 comments
0
51

As is the norm in Python there are several ways to do this. In all examples assume: lst = [1, 2, 3, 4, 5]

1. Using enumerate (considered most idiomatic)

for index, element in enumerate(lst):
    # do the things that need doing here

This is also the safest option in my opinion because the chance of going into infinite recursion has been eliminated. Both the item and its index are held in variables and there is no need to write any further code to access the item.

2. Creating a variable to hold the index (using for)

for index in range(len(lst)):   # or xrange
    # you will have to write extra code to get the element

3. Creating a variable to hold the index (using while)

index = 0
while index < len(lst):
    # you will have to write extra code to get the element
    index += 1  # escape infinite recursion

4. There is always another way

As explained before, there are other ways to do this that have not been explained here and they may even apply more in other situations. e.g using itertools.chain with for. It handles nested loops better than the other examples.

15.08.2017 02:17
5
34

Old fashioned way:

for ix in range(len(ints)):
    print(ints[ix])

List comprehension:

[ (ix, ints[ix]) for ix in range(len(ints))]

>>> ints
[1, 2, 3, 4, 5]
>>> for ix in range(len(ints)): print ints[ix]
... 
1
2
3
4
5
>>> [ (ix, ints[ix]) for ix in range(len(ints))]
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
>>> lc = [ (ix, ints[ix]) for ix in range(len(ints))]
>>> for tup in lc:
...     print(tup)
... 
(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
>>> 
06.02.2009 22:52
Comments
This is not wrong and is used in C/C++ and others. It's considered as non-pythonic, but can also be used in python. Like simple solutions that break it down to the source :+ by Valor Naram, 29.07.2018 20:57
Some python extremists would say, don't do this. But I said it only to indicate that there is more than one possible way by Valor Naram, 30.07.2018 13:51
niiice, something c users can understand by Ahmad, 29.12.2020 00:15
"Old-fashioned" doesn't actually mean "wrong" by Charlie Martin, 29.12.2020 15:36
@CharlieMartin THIS was a GENIUS Answer! Thanks SO MUCH for posting this; It helped A LOT ! [+10/10] by William Martens, 18.03.2021 11:35
3
33

Accessing indexes & Performance Benchmarking of approaches

The fastest way to access indexes of list within loop in Python 3.7 is to use the enumerate method for small, medium and huge lists.

Please see different approaches which can be used to iterate over list and access index value and their performance metrics (which I suppose would be useful for you) in code samples below:

# Using range
def range_loop(iterable):
    for i in range(len(iterable)):
        1 + iterable[i]

# Using enumerate
def enumerate_loop(iterable):
    for i, val in enumerate(iterable):
        1 + val

# Manual indexing
def manual_indexing_loop(iterable):
    index = 0
    for item in iterable:
        1 + item
        index += 1

See performance metrics for each method below:

from timeit import timeit

def measure(l, number=10000):
    print("Measure speed for list with %d items" % len(l))
    print("range: ", timeit(lambda :range_loop(l), number=number))
    print("enumerate: ", timeit(lambda :enumerate_loop(l), number=number))
    print("manual_indexing: ", timeit(lambda :manual_indexing_loop(l), number=number))

# Measure speed for list with 1000 items
measure(range(1000))
# range:  1.161622366
# enumerate:  0.5661940879999996
# manual_indexing:  0.610455682

# Measure speed for list with 100000 items
measure(range(10000))
# range:  11.794482958
# enumerate:  6.197628574000001
# manual_indexing:  6.935181098000001

# Measure speed for list with 10000000 items
measure(range(10000000), number=100)
# range:  121.416859069
# enumerate:  62.718909123
# manual_indexing:  69.59575057400002

As the result, using enumerate method is the fastest method for iteration when the index needed.

Adding some useful links below:

04.08.2016 09:49
Comments
"readability counts" The speed difference in the small <1000 range is insignificant. It is 3% slower on an already small time metric. by User, 04.03.2017 00:08
How about updating the answer to Python 3? by Georgy, 22.05.2019 14:20
@Georgy makes sense, on python 3.7 enumerate is total winner :) by Andriy Ivaneyko, 16.06.2020 09:22
3
13

According to this discussion: http://bytes.com/topic/python/answers/464012-objects-list-index

Loop counter iteration

The current idiom for looping over the indices makes use of the built-in range function:

for i in range(len(sequence)):
    # work with index i

Looping over both elements and indices can be achieved either by the old idiom or by using the new zip built-in function:

for i in range(len(sequence)):
    e = sequence[i]
    # work with index i and element e

or

for i, e in zip(range(len(sequence)), sequence):
    # work with index i and element e

via http://www.python.org/dev/peps/pep-0212/

05.05.2012 07:10
Comments
This won't work for iterating through generators. Just use enumerate(). by Tadeck, 31.03.2013 18:24
Nowadays, the current idiom is enumerate, not the range call. by TankorSmash, 15.08.2016 18:12
and it's the same as the older answer: stackoverflow.com/a/522576/6451573 by Jean-François Fabre, 20.04.2019 12:54
0
14

First of all, the indexes will be from 0 to 4. Programming languages start counting from 0; don't forget that or you will come across an index out of bounds exception. All you need in the for loop is a variable counting from 0 to 4 like so:

for x in range(0, 5):

Keep in mind that I wrote 0 to 5 because the loop stops one number before the max. :)

To get the value of an index use

list[index]
25.05.2015 15:08
0
12

You can do it with this code:

ints = [8, 23, 45, 12, 78]
index = 0

for value in (ints):
    index +=1
    print index, value

Use this code if you need to reset the index value at the end of the loop:

ints = [8, 23, 45, 12, 78]
index = 0

for value in (ints):
    index +=1
    print index, value
    if index >= len(ints)-1:
        index = 0
25.05.2015 15:26
0
16

Here's what you get when you're accessing index in for loops:

for i in enumerate(items): print(i)

items = [8, 23, 45, 12, 78]

for i in enumerate(items):
    print("index/value", i)

Result:

# index/value (0, 8)
# index/value (1, 23)
# index/value (2, 45)
# index/value (3, 12)
# index/value (4, 78)

for i, val in enumerate(items): print(i, val)

items = [8, 23, 45, 12, 78]

for i, val in enumerate(items):
    print("index", i, "for value", val)

Result:

# index 0 for value 8
# index 1 for value 23
# index 2 for value 45
# index 3 for value 12
# index 4 for value 78

for i, val in enumerate(items): print(i)

items = [8, 23, 45, 12, 78]

for i, val in enumerate(items):
    print("index", i)

Result:

# index 0
# index 1
# index 2
# index 3
# index 4
17.01.2019 01:07
0
12

If I were to iterate nums = [1, 2, 3, 4, 5] I would do

for i, num in enumerate(nums, start=1):
    print(i, num)

Or get the length as l = len(nums)

for i in range(l):
    print(i+1, nums[i])
04.06.2018 02:10
0
11

The best solution for this problem is to use the enumerate builtin function.

enumerate returns a tuple, where the first value is the index and the second value is the element of the list at that index.

In [1]: ints = [8, 23, 45, 12, 78]

In [2]: for idx, val in enumerate(ints):
   ...:         print(idx, val)
   ...:     
(0, 8)
(1, 23)
(2, 45)
(3, 12)
(4, 78)
24.08.2017 06:15
2
6

If there is no duplicate value in the list:

for i in ints:
    indx = ints.index(i)
    print(i, indx)
10.06.2018 03:59
Comments
Note that the first option should not be used, since it only works correctly only when each item in the sequence is unique. by Stam Kaly, 19.12.2018 14:05
First option is O(n²), a terrible idea. If your list is 1000 elements long, it'll take literally a 1000 times longer than using enumerate. You should delete this answer. by Boris, 20.04.2019 10:24
0
10

In your question, you write "how do I access the loop index, from 1 to 5 in this case?"

However, the index for a list runs from zero. So, then we need to know if what you actually want is the index and item for each item in a list, or whether you really want numbers starting from 1. Fortunately, in Python, it is easy to do either or both.

First, to clarify, the enumerate function iteratively returns the index and corresponding item for each item in a list.

alist = [1, 2, 3, 4, 5]

for n, a in enumerate(alist):
    print("%d %d" % (n, a))

The output for the above is then,

0 1
1 2
2 3
3 4
4 5

Notice that the index runs from 0. This kind of indexing is common among modern programming languages including Python and C.

If you want your loop to span a part of the list, you can use the standard Python syntax for a part of the list. For example, to loop from the second item in a list up to but not including the last item, you could use

for n, a in enumerate(alist[1:-1]):
    print("%d %d" % (n, a))

Note that once again, the output index runs from 0,

0 2
1 3
2 4

That brings us to the start=n switch for enumerate(). This simply offsets the index, you can equivalently simply add a number to the index inside the loop.

for n, a in enumerate(alist, start=1):
    print("%d %d" % (n, a))

for which the output is

1 1
2 2
3 3
4 4
5 5
15.08.2018 17:52
0
6

You can also try this:

data = ['itemA.ABC', 'itemB.defg', 'itemC.drug', 'itemD.ashok']
x = []
for (i, item) in enumerate(data):
      a = (i, str(item).split('.'))
      x.append(a)
for index, value in x:
     print(index, value)

The output is

0 ['itemA', 'ABC']
1 ['itemB', 'defg']
2 ['itemC', 'drug']
3 ['itemD', 'ashok']
07.02.2018 14:04
2
1

This serves the purpose well enough:

list1 = [10, 'sumit', 43.21, 'kumar', '43', 'test', 3]
for x in list1:
    print('index:', list1.index(x), 'value:', x)
24.04.2018 10:45
Comments
This will break down if there are repeated elements in the list as index() will search for the first occurrence of x, not mentioning the O( n^2 ) time required to look up each element. by Peter Szoldan, 15.05.2018 17:17
totally agreed that it won't work for duplicate elements in the list. afterall I'm also learning python. by Sumit Kumar, 06.06.2018 10:16
0
4

Simple answer using While Loop:

arr = [8, 23, 45, 12, 78]
i = 0
while i < len(arr):
    print("Item ", i + 1, " = ", arr[i])
    i += 1

Output:

enter image description here

18.04.2020 20:25
0
4

You can use the index method

ints = [8, 23, 45, 12, 78]
inds = [ints.index(i) for i in ints]

EDIT Highlighted in the comment that this method doesn’t work if there are duplicates in ints, the method below should work for any values in ints:

ints = [8, 8, 8, 23, 45, 12, 78]
inds = [tup[0] for tup in enumerate(ints)]

Or alternatively

ints = [8, 8, 8, 23, 45, 12, 78]
inds = [tup for tup in enumerate(ints)]

if you want to get both the index and the value in ints as a list of tuples.

It uses the method of enumerate in the selected answer to this question, but with list comprehension, making it faster with less code.

30.05.2018 21:34
0
2

To print tuple of (index, value) in list comprehension using a for loop:

ints = [8, 23, 45, 12, 78]
print [(i,ints[i]) for i in range(len(ints))]

Output:

[(0, 8), (1, 23), (2, 45), (3, 12), (4, 78)]
24.04.2018 10:53
0
0

Use enumerate to iterate over the list

ints = [8, 23, 45, 12, 78]
for idx,val in enumerate(ints):
    print('item #{} = {}'.format(idx+1, val))

Output:

item #1 = 8
item #2 = 23
item #3 = 45
item #4 = 12
item #5 = 78
30.03.2021 17:30
0
0

You can simply use count variable to count the number of elements in the list

ints = [8, 23, 45, 12, 78]
count = 0
for i in ints:
    count = count + 1
    print('item #{} = {}'.format(count, i))
09.05.2021 19:19