Python
list iteration
index
duplicate question
programming tips

Iterate a list with indexes

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Iterating over a list with indexes is a basic Python task, but there is a right way and several weaker alternatives. The idiomatic solution is usually enumerate, which gives you both position and value without manual counter management. Knowing when to use enumerate, when to use range, and when to avoid indexes entirely makes loop code clearer and less error-prone.

Use enumerate as the Default Pattern

For most read-only loops where you need both the item and its position, use enumerate.

python
1names = ["Ada", "Grace", "Linus"]
2
3for index, name in enumerate(names):
4    print(index, name)

This is preferred over manual index tracking because it is explicit and avoids bookkeeping bugs.

You can also start counting from a custom value:

python
1items = ["apple", "banana", "orange"]
2
3for position, item in enumerate(items, start=1):
4    print(position, item)

That is useful for user-facing numbering where counting should begin at 1 instead of 0.

Use range(len(...)) Only When You Need Index-Based Access

Sometimes the loop logic really depends on indexing, such as looking at neighboring elements or mutating the list by position.

python
1values = [10, 20, 30, 40]
2
3for i in range(len(values)):
4    print(i, values[i])

This is valid, but it is more verbose than enumerate. Use it when the index itself is part of the algorithm, not just because it feels familiar.

For example, comparing adjacent elements naturally uses index arithmetic:

python
1numbers = [3, 8, 8, 12]
2
3for i in range(1, len(numbers)):
4    prev_value = numbers[i - 1]
5    current_value = numbers[i]
6    print(i, prev_value, current_value)

In this kind of loop, range is the correct tool.

Modify List Elements by Index Safely

If you need to replace values inside the same list, loop by index rather than by element value.

python
1prices = [100, 250, 300]
2
3for i, value in enumerate(prices):
4    prices[i] = value * 2
5
6print(prices)

This works because you are writing back to the original list by position.

Be careful with structural changes such as inserting or removing elements while iterating. That can shift indexes and produce hard-to-debug behavior. If you need heavy modification, build a new list instead.

python
1scores = [55, 72, 90]
2adjusted = []
3
4for i, score in enumerate(scores):
5    adjusted.append(score + 5)
6
7print(adjusted)

Avoid Indexes When You Do Not Need Them

A lot of code uses indexes unnecessarily. If you only need the values, loop over the values directly.

python
1colors = ["red", "green", "blue"]
2
3for color in colors:
4    print(color)

This is simpler than introducing an index you never use.

Likewise, if you need parallel iteration across two sequences, zip is often clearer than managing indexes manually.

python
1names = ["Ada", "Grace", "Linus"]
2scores = [98, 95, 91]
3
4for name, score in zip(names, scores):
5    print(name, score)

Use indexes when they add value, not by default.

Combine Index Logic with Conditions

Index-aware loops are often useful for formatting and positional rules.

python
1words = ["alpha", "beta", "gamma", "delta"]
2
3for i, word in enumerate(words):
4    if i % 2 == 0:
5        print("even index:", i, word)
6    else:
7        print("odd index:", i, word)

This pattern is common in reporting, alternating row styles, and sequence-based algorithms.

Iterating Nested Lists with Indexes

For tables or grid-like data, nested enumerate calls keep both row and column positions available.

python
1grid = [
2    [1, 2, 3],
3    [4, 5, 6],
4]
5
6for row_index, row in enumerate(grid):
7    for col_index, value in enumerate(row):
8        print(row_index, col_index, value)

This is much clearer than manually incrementing counters at two levels.

Performance and Readability Tradeoff

In normal application code, readability matters more than tiny loop micro-optimizations. enumerate is both idiomatic and efficient enough for most workloads.

If you are working in a tight numerical loop, measure before changing style for performance reasons. In many cases, the surrounding algorithm matters far more than the difference between enumerate and range(len(...)).

Common Pitfalls

One common mistake is using range(len(items)) when only the values are needed. That makes code noisier without adding useful information.

Another issue is modifying list structure while iterating with indexes. Removing or inserting items can invalidate index assumptions mid-loop.

A third mistake is shadowing the meaning of the index variable by reusing it for unrelated logic inside the loop body.

Summary

  • Use enumerate as the standard way to iterate over a list with indexes in Python.
  • Use range(len(...)) only when you genuinely need index arithmetic or positional writes.
  • Iterate over values directly when indexes are unnecessary.
  • Prefer building a new list over mutating structure during indexed iteration.
  • Choose the loop form that matches the algorithm, not just habit.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.