5249

How do I access the index while iterating over a sequence with a for loop?

xs = [8, 23, 45]

for x in xs:
    print("item #{} = {}".format(index, x))

Desired output:

item #1 = 8
item #2 = 23
item #3 = 45
cottontail
  • 10,268
  • 18
  • 50
  • 51
Joan Venge
  • 315,713
  • 212
  • 479
  • 689
  • 105
    Note that indexes in python start from 0, so the indexes for your example list are 0 to 4 not 1 to 5 – plugwash Oct 02 '18 at 16:54

27 Answers27

8660

Use the built-in function enumerate():

for idx, x in enumerate(xs):
    print(idx, x)

It is non-pythonic to manually index via for i in range(len(xs)): x = xs[i] or manually manage an additional state variable.

Check out PEP 279 for more.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Mike Hordecki
  • 92,113
  • 3
  • 26
  • 27
  • 137
    As Aaron points out below, use start=1 if you want to get 1-5 instead of 0-4. – clozach Mar 31 '18 at 22:16
  • 9
    Does `enumerate` not incur another overhead? – TheRealChx101 Oct 17 '19 at 23:03
  • 10
    @TheRealChx101 according to my tests (Python 3.6.3) the difference is negligible and sometimes even in favour of `enumerate`. – Błotosmętek Feb 07 '20 at 12:18
  • 23
    @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 `tuple`s 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). – ShadowRanger Oct 06 '20 at 18:19
  • Why does python not have a professional for loop syntax to perform this universally common operation? – user2585501 Oct 07 '21 at 00:59
  • 7
    @user2585501. It does: `for i in range(5)` or `for i in range(len(ints))` will do the universally common operation of iterating over an index. But if you want both the item ***and*** the index, `enumerate` is a _very_ useful syntax. I use it all the time. – bfris Oct 14 '21 at 19:10
  • The performance impact of using enumerate with unpacking is significantly lower compared to the overhead incurred by looping over a range and indexing each time, or manually tracking and updating the index separately. The enumerate function with unpacking syntax is highly optimized for efficiency. – Dmitrii Malygin May 17 '23 at 12:22
1266

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:

count = 0 # in case items is empty and you need it after the loop
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.

count = 0 # in case items is empty
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)
Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • 4
    Does the "*Getting a count*" example work when `items` is empty? – Bergi Feb 22 '20 at 15:36
  • 3
    @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). – ShadowRanger Oct 06 '20 at 18:21
  • 2
    Brilliant and comprehensive answer which explains the difference between idiomatic (aka pythonic ) rather than just stating that a particular approach is unidiomatic (i.e. non-pythonic) without explanation. – nerak99 Aug 18 '22 at 08:09
258

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) # Migrate to print() after 3.x+
   
SuperStormer
  • 4,997
  • 5
  • 25
  • 35
A.J.
  • 8,557
  • 11
  • 61
  • 89
  • 16
    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)`. – Antti Haapala -- Слава Україні Mar 18 '16 at 09:18
  • 1
    Better is to enclose index inside parenthesis pairs as (index), it will work on both the Python versions 2 and 3. – hygull Jan 02 '18 at 11:31
  • 2
    @AnttiHaapala The reason, I presume, is that the question's expected output starts at index 1 instead 0 – pushkin Nov 30 '18 at 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. – ShadowRanger Oct 06 '20 at 18:23
136
for i in range(len(ints)):
   print(i, ints[i]) # print updated to print() in Python 3.x+ 
mhhabib
  • 2,975
  • 1
  • 15
  • 29
David Hanak
  • 10,754
  • 3
  • 31
  • 39
  • 11
    That should probably be `xrange` for pre-3.0. – Ben Blank Feb 06 '09 at 22:52
  • 67
    Use enumerate instead – saulspatz Aug 01 '15 at 21:28
  • 5
    For Python 2.3 above, use enumerate built-in function since it is more Pythonic. – januarvs Mar 15 '17 at 06:31
  • 2
    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. – adg Mar 31 '17 at 23:18
  • 4
    @adg I don't see how avoid `enumerate` saves any logic; you still have to select which object to index with `i`, no? – chepner Sep 15 '17 at 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. – Graham Dec 23 '18 at 16:33
  • This representation is useful when I use numba or cython. – naoki fujita May 07 '19 at 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. – ShadowRanger Oct 06 '20 at 18:27
  • @saulspatz, repeating some code N times is not best with enumerate though. –  vrnvorona Jun 10 '23 at 21:55
114

Tested on Python 3.12

Here are twelve examples of how you can access the indices with their corresponding array's elements using for loops, while loops and some looping functions. Note that array indices always start from zero by default (see example 4 to change this).

1. Looping elements with counter and += operator.

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

for value in items:
    print(counter, value)
    counter += 1

Result:

#    0 8
#    1 23
#    2 45
#    3 12
#    4 78

2. Iterating elements using enumerate() built-in function.

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)

3. Getting list's element and its index separately.

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

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

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

4. You can change the index value to any increment.

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

for i, item in enumerate(items, start=100):
    print(i, item)

Result:

#    100 8
#    101 23
#    102 45
#    103 12
#    104 78

5. Automatic counter incrementation with range(len(...)) methods.

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

for i in range(len(items)):
    print("Index:", i, "Value:", items[i])

Result:

#    ('Index:', 0, 'Value:', 8)
#    ('Index:', 1, 'Value:', 23)
#    ('Index:', 2, 'Value:', 45)
#    ('Index:', 3, 'Value:', 12)
#    ('Index:', 4, 'Value:', 78)

6. Using for loop inside function.

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

def enum(items, start=0):
    counter = start

    for value in items:
        print(counter, value)
        counter += 1
    
enum(items)

Result:

#    0 8
#    1 23
#    2 45
#    3 12
#    4 78

7. Of course, we can't forget about while loop.

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

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

Result:

#    0 8
#    1 23
#    2 45
#    3 12
#    4 78

8. yield statement returning a generator object.

def createGenerator():        
    items = [8, 23, 45, 12, 78]

    for (j, k) in enumerate(items):
        yield (j, k)
        

generator = createGenerator()

for i in generator:
    print(i)

Result:

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

9. Inline expression with for loop and lambda.

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

xerox = lambda upperBound: [(i, items[i]) for i in range(0, upperBound)]
print(xerox(5))

Result:

#    [(0, 8), (1, 23), (2, 45), (3, 12), (4, 78)]

10. Iterate over two lists at once using Python's zip() function.

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

for index in range(len(items)):
    indices.append(index)

for item, index in zip(items, indices):
    print("{}: {}".format(index, item))

Result:

#    0: 8
#    1: 23
#    2: 45
#    3: 12
#    4: 78

11. Loop over 2 lists with a while loop and iter() & next() methods.

items = [8, 23, 45, 12, 78]
indices = range(len(items))

iterator1 = iter(indices)
iterator2 = iter(items)
  
try:
    while True:
        i = next(iterator1)
        element = next(iterator2)
        print(i, element)
except StopIteration:
    pass

Result:

#    0  8
#    1  23
#    2  45
#    3  12
#    4  78

12. Also, it's nice to iterate list's elements inside class' Static Method.

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

class ElementPlus:
    @staticmethod                            # decorator
    def indexForEachOfMy(iterable):
        for pair in enumerate(iterable):
            print pair

ElementPlus.indexForEachOfMy(items)

Result:

#    (0, 8)
#    (1, 23)
#    (2, 45)
#    (3, 12)
#    (4, 78)
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    Thanks for the really detailed answer showing all variations of how to achieve that. Should be the accepted answer in my opinion! – zomilanovic Aug 14 '23 at 08:23
66

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.

  1. 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
  1. 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
  1. 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. For example, using itertools.chain with for. It handles nested loops better than the other examples.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Charitoo
  • 1,814
  • 17
  • 21
48

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:

Community
  • 1
  • 1
Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
48

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)
>>> 
mhhabib
  • 2,975
  • 1
  • 15
  • 29
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • 5
    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 :+ –  Jul 29 '18 at 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 –  Jul 30 '18 at 13:51
41

You can use enumerate and embed expressions inside string literals to obtain the solution.

This is a simple way:

a=[4,5,6,8]
for b, val in enumerate(a):
    print('item #{} = {}'.format(b+1, val))
Lars
  • 1,006
  • 1
  • 9
  • 29
Kofi
  • 1,224
  • 1
  • 10
  • 21
22

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 maximum. :)

To get the value of an index, use

list[index]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rassa45
  • 3,482
  • 1
  • 29
  • 43
20

According to this discussion: object's 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 PEP 212 – Loop Counter Iteration.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
thinker007
  • 527
  • 4
  • 6
20

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
Liam
  • 6,009
  • 4
  • 39
  • 53
19

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])
so2
  • 322
  • 2
  • 13
Ankur Kothari
  • 822
  • 9
  • 11
19

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
Georgy
  • 12,464
  • 7
  • 65
  • 73
DrM
  • 2,404
  • 15
  • 29
14

If there is no duplicate value in the list:

for i in ints:
    indx = ints.index(i)
    print(i, indx)
Georgy
  • 12,464
  • 7
  • 65
  • 73
RIshu
  • 227
  • 3
  • 11
  • 2
    Note that the first option should not be used, since it only works correctly only when each item in the sequence is unique. – Stam Kaly Dec 19 '18 at 14:05
  • 6
    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. – Boris Verkhovskiy Apr 20 '19 at 10:24
11

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']
Ashok Kumar Jayaraman
  • 2,887
  • 2
  • 32
  • 40
8

You can use the index method:

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

It is highlighted in a 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
PyRsquared
  • 6,970
  • 11
  • 50
  • 86
8

A simple answer using a while loop:

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

Output:

Item  1  =  8
Item  2  =  23
Item  3  =  45
Item  4  =  12
Item  5  =  78
Amar Kumar
  • 2,392
  • 2
  • 25
  • 33
  • Please review *[Should we edit a question to transcribe code from an image to text?](https://meta.stackoverflow.com/questions/415040)* and *[Why not upload images of code/errors when asking a question?](https://meta.stackoverflow.com/questions/285551/)* (e.g., *"Images should only be used to illustrate problems that* ***can't be made clear in any other way,*** *such as to provide screenshots of a user interface."*) and take the appropriate [action](https://stackoverflow.com/posts/61295753/edit) (it covers answers as well). Thanks in advance. – Peter Mortensen Apr 20 '22 at 13:06
6

To print a tuple of (index, value) in a 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)]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lola
  • 115
  • 2
  • 6
6

You can simply use a variable such as count 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))
Sam
  • 21
  • 7
Rahul
  • 179
  • 2
  • 4
3

In addition to all the excellent answers above, here is a solution to this problem when working with pandas Series objects. In many cases, pandas Series have custom/unique indices (for example, unique identifier strings) that can't be accessed with the enumerate() function.

xs = pd.Series([8, 23, 45])

xs.index = ['G923002', 'G923004', 'G923005']

print(xs)

Output:

#    G923002     8
#    G923004    23
#    G923005    45
#    dtype: int64

We can see below that enumerate() doesn't give us the desired result:

for id, x in enumerate(xs):
    print("id #{} = {}".format(id, x))

Output:

#    id #0 = 8
#    id #1 = 23
#    id #2 = 45

We can access the indices of a pandas Series in a for loop using .items():

for id, x in xs.items():
    print("id #{} = {}".format(id, x))

Output:

#    id #G923002 = 8
#    id #G923004 = 23
#    id #G923005 = 45
jglad
  • 120
  • 2
  • 2
  • 13
3

One-liner lovers:

[index for index, datum in enumerate(data) if 'a' in datum]

Explaination:

>>> data = ['a','ab','bb','ba','alskdhkjl','hkjferht','lal']
>>> data
['a', 'ab', 'bb', 'ba', 'alskdhkjl', 'hkjferht', 'lal']
>>> [index for index, datum in enumerate(data) if 'a' in datum]
[0, 1, 3, 4, 6]
>>> [index for index, datum in enumerate(data) if 'b' in datum]
[1, 2, 3]
>>>

Points to take:

  • Python list doesn't provide an index; if you are using for
  • If you enumerate a list it will return you ANOTHER list
    • BUT that list will have a different type
    • it will wrap each and every element with an index as tuple
    • we can access tuples as variables, separated with comma(,)

Thanks. Keep me in your prayers.

Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
2

You can use range(len(some_list)) and then lookup the index like this

xs = [8, 23, 45]
for i in range(len(xs)):
    print("item #{} = {}".format(i + 1, xs[i]))

Or use the Python’s built-in enumerate function which allows you to loop over a list and retrieve the index and the value of each item in the list

xs = [8, 23, 45]
for idx, val in enumerate(xs, start=1):
    print("item #{} = {}".format(idx, val))
Ran Turner
  • 14,906
  • 5
  • 47
  • 53
1

Yet another way to run a counter in a for loop is to use itertools.count.

from itertools import count

my_list = ['a', 'b', 'a']
for i, item in zip(count(), my_list):
    print(i, item)

This is useful especially if you want the counters to be fractional numbers. In the following example, the "index" starts from 1.0 and is incremented by 0.5 in each iteration.

my_list = ['a', 'b', 'a']

for i, item in zip(count(start=1., step=0.5), my_list):
    print(f"loc={i}, item={item}")
    
# loc=1.0, item=a
# loc=1.5, item=b
# loc=2.0, item=a

Another method is to use list.index() inside a loop. However, in contrast to other answers on this page mentioning this method (1, 2, 3), the starting point of the index search (which is the second argument) must be passed to the list.index() method. This lets you achieve 2 things: (1) Doesn't expensively loop over the list from the beginning again; (2) Can find the index of all values, even duplicates.

my_list = ['a', 'b', 'a']
idx = -1
for item in my_list:
    idx = my_list.index(item, idx+1)
    #                         ^^^^^   <---- start the search from the next index
    print(f"index={idx}, item={item}")
    
# index=0, item=a
# index=1, item=b
# index=2, item=a

In terms of performance, if you want all/most of the indices, enumerate() is the fastest option. If you were looking for only specific indices, then list.index() may be more efficient. Below are two examples where list.index() is more efficient.

Example #1: Index of specific values

Suppose you want to find all indices where a specific value appears in a list (e.g. highest value). For example, in the following case, we want to find all indices that 2 appears in. This is a one-liner using enumerate(). However, we can also search for the indices of 2 by using the list.index() method in a while-loop; as mentioned before, in each iteration, we start the index search from where we left off in the previous iteration.

lst = [0, 2, 1, 2]
target = 2

result = []
pos = -1
while True:
    try:
        pos = lst.index(target, pos+1)
        result.append(pos)
    except ValueError:
        break
        
print(result)      # [1, 3]

In fact, in certain cases, it's much faster than enumerate() option that produces the same output especially if the list is long.

Example #2: Index of the first number that is smaller than a target

Another common exercise where index is often needed in a loop is to find the index of the first item in a list that satisfies some condition (e.g. greater/smaller than some target value). In the following example, we want to find the index of the first value that exceeds 2.5. This is a one-liner using enumerate() but using list.index() is more efficient because getting indices that won't be used as in enumerate() has a cost (which list.index() doesn't incur).

my_list = [1, 2, 3, 4]
target = 2.5

for item in my_list:
    if item > target:
        idx = my_list.index(item)
        break

or as a one-liner:

idx = next(my_list.index(item) for item in my_list if item > target)

benchmark


Code used to produce the plot of runtime speed ratios:

import random
import matplotlib.pyplot as plt
import perfplot


def enumerate_1(lst, target=3):
    return [i for i, v in enumerate(lst) if v == target]


def list_index_1(lst, target=3):
    result = []
    pos = -1
    while True:
        try:
            pos = lst.index(target, pos+1)
            result.append(pos)
        except ValueError:
            break
    return result


def list_index_2(lst, target):
    for item in lst:
        if item > target:
            return lst.index(item)


def enumerate_2(lst, target):
    return next(i for i, item in enumerate(lst) if item > target)


setups = [lambda n: [random.randint(1, 10) for _ in range(n)], 
          lambda n: (list(range(n)), n-1.5)]
kernels_list = [[enumerate_1, list_index_1], [enumerate_2, list_index_2]]
titles = ['Get indices of a value', 'Get index that satisfies a condition']
n_range = [2**k for k in range(1,21)]
labels = ['enumerate', 'list.index']
xlabel = 'list length'

fig, axs = plt.subplots(1, 2, figsize=(10, 5), facecolor='white', dpi=60)
for i, (ax, su, ks, t) in enumerate(zip(axs, setups, kernels_list, titles)):
    plt.sca(ax)
    perfplot.plot(ks, n_range, su, None, labels, xlabel, t, relative_to=1)
    ax.xaxis.set_tick_params(labelsize=13)
plt.setp(axs, ylim=(0.7, 2.4), yticks=[i*0.25 + 0.75 for i in range(7)], 
         xlim=(1, 1100000), xscale='log', xticks=[1, 100, 10000, 1000000])
fig.tight_layout();
cottontail
  • 10,268
  • 18
  • 50
  • 51
  • @KellyBundy I edited the second benchmark. Now the found index will always be near the end; random shuffling is not really needed here. Thanks for pointing me to the error. – cottontail Aug 24 '23 at 07:32
  • 1
    Nicely done. And index() beating enumerate() in the second scenario despite the two passes is something I've been telling/showing people a few times, I might point them here from now on :-) – Kelly Bundy Aug 24 '23 at 10:25
0

It can be achieved with the following code:

xs = [8, 23, 45]
for x, n in zip(xs, range(1, len(xs)+1)):
    print("item #{} = {}".format(n, x))

Here, range(1, len(xs)+1); If you expect the output to start from 1 instead of 0, you need to start the range from 1 and add 1 to the total length estimated since python starts indexing the number from 0 by default.

Final Output:
item #1 = 8
item #2 = 23
item #3 = 45
kamalesh d
  • 17
  • 1
  • 4
-4

A loop with a "counter" variable set as an initialiser that will be a parameter, in formatting the string, as the item number.

The for loop accesses the "listos" variable which is the list. As we access the list by "i", "i" is formatted as the item price (or whatever it is).

listos = [8, 23, 45, 12, 78]
counter = 1
for i in listos:
    print('Item #{} = {}'.format(counter, i))
    counter += 1

Output:

Item #1 = 8
Item #2 = 23
Item #3 = 45
Item #4 = 12
Item #5 = 78
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
LunaticXXD10
  • 421
  • 4
  • 10
  • @calculuswhiz the while loop is an important code snippet. the initialiser "counter" is used for item number. About Indentation: The guy must be enough aware about programming that indentation matters. so after you do your special attribute...{copy paste} you can still edit the indentation. *And the code runs very nicely and smoothly* – LunaticXXD10 Jan 08 '22 at 15:25
  • 1
    @LunaticXXD10 In your *original post*, which you can see in the edit history, `counter += 1` was indented at the same level as the `for` loop. In that case, it would have updated per iteration of the `for` loop. Here, it updates per iteration of the `while` loop. My question on the `while` loop remains: Why is it necessary to use a while loop when counter can be updated in the `for` loop? This is plainly visible in [Rahul's answer](https://stackoverflow.com/a/67461537/4294399). – General Grievance Jan 09 '22 at 22:06
  • 1
    Re *"...must be enough aware about programming that indentation matters"*: Well, computers are quite literally minded. – Peter Mortensen Apr 20 '22 at 13:20
-6

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)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sumit Kumar
  • 125
  • 1
  • 5
  • 15
    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. – Peter Szoldan May 15 '18 at 17:17
  • totally agreed that it won't work for duplicate elements in the list. afterall I'm also learning python. – Sumit Kumar Jun 06 '18 at 10:16
  • The accepted suggested edit by user *Raj kumar* resulted in the error *"NameError: name 'list1' is not defined"* – Peter Mortensen Apr 20 '22 at 12:07