Concepts / Iterating Through Lists with for Loops

Iterating Through Lists with for Loops

Index-based iteration combines range() and len() to generate indices, enabling you to read and modify list elements.

  • Programming
Interactive lab

Try it: Loop Tracer

How a Python for loop visits each item in turn, and how an accumulator variable (a total, a count, a best-so-far or a result list) changes on every iteration.

How it works

  1. Initialise the accumulator before the loop.
  2. Each iteration, the loop variable takes the next value from the list.
  3. An if inside the loop decides whether to update the accumulator.
  4. After the last item the loop ends and the accumulator holds the answer.

Default run (13 steps): values = [4, 9, 2, 7, 5]. Run the loop one statement at a time. … The loop has used every value. print(total) shows 27.

Simplified: A model of five fixed loop programs (sum, count, maximum, minimum, filter) run on your list — it steps the program exactly as Python would, but it does not run Python.

Educational simulation

Loading the simulation…

Why the Index Matters

A for loop can move through a list by using the list's values, but some tasks require the position of each value as well. Index-based iteration combines range() and len() to generate indices. Those indices let a loop locate a list element, read its current value, and assign a new value back to that same position.

What do you think happens?

Suppose a loop uses the assignment numbers[i] = numbers[i] * 2. What does the statement do at the current index?

  • It reads the current value and writes a new value at the same position
  • It only reads the value and leaves the list unchanged
  • It removes the current element from the list
Reveal answer

Answer: It reads the current value and writes a new value at the same position

The expression on the right reads the old value at index i, multiplies it by 2, and the assignment writes the result back to index i.

Mapping Indices to Elements

The expression len(list) supplies the list length, and range(len(list)) is used to generate the indices needed for the loop. The loop variable represents the current index. Writing list[i] then refers to the element at that position, so the same index can be used to inspect or update the corresponding list element.

selectsselectsselects0first positionnumbers[0]first element1second positionnumbers[1]second element2third positionnumbers[2]third element
Which generated index is paired with each list element?
python

Reading and Reassigning

Doubling Each Element

Trace the assignment numbers[i] = numbers[i] * 2 as the loop processes a list.

Read: At the current index i, numbers[i] on the right side supplies the old value.

Calculate: The old value is multiplied by 2.

Assign: The result is written to numbers[i], replacing the old value at the same position.

Each processed element receives a new value equal to its old value multiplied by 2.

readwriteold valuenumbers[i]multiply by 2numbers[i] * 2new valuenumbers[i]
How does the value at the current index move from its old state to its new state?

The two appearances of numbers[i] have different roles. On the right side, numbers[i] is read as the old value. On the left side, numbers[i] identifies where the calculated result is written. This is why one assignment can both inspect and update the current list element.

Following the Loop Flow

supplies lengthprovidesselectsthenlen(numbers)list lengthrange(len(numbers))generated indicescurrent index iselect positionnumbers[i]read or update elementnext indexcontinue loop
What happens as an index-based loop obtains the list length, selects an index, accesses an element, and advances?

A useful trace follows the loop in order: determine the list length, use range(len(list)) to provide indices, use the current index to access the element, perform the read or update, and then continue to the next generated index. Tracing makes the final list state predictable instead of treating the loop as one unexplained action.

Tracing Every Update

update index 0update index 1update index 2loop completenumbers[1, 2, 3]i = 0[2, 2, 3]i = 1[2, 4, 3]i = 2[2, 4, 6]final numbers[2, 4, 6]
What is the list's state before and after each update, and what final list results?

Predicting the Final List

Start with numbers = [1, 2, 3] and apply numbers[i] = numbers[i] * 2 during each iteration.

Initial state: The list begins as [1, 2, 3].

First update: The current element has value 1. Multiplying it by 2 changes the list to [2, 2, 3].

Second update: The current element has value 2. Multiplying it by 2 changes the list to [2, 4, 3].

Third update: The current element has value 3. Multiplying it by 2 changes the list to [2, 4, 6].

The final list is [2, 4, 6].

The important tracing habit is to record the list after every assignment. Only the element at the current index changes during that step. Previously updated elements keep their new values, while elements not yet reached still have their old values.

Choosing the Loop Style

Loop purposePreferred approachReason
Read list elementsValue-based iterationUse this when the values only need to be inspected.
Update list elementsIndex-based iteration with range() and len()Use the index to write a new value back to the element's position.
locateslist valuesread onlyindex iselect positionlist elementwrite new value
What changes when a loop only reads values compared with when it must update list elements?

Mistakes in Loop Traces

  • Treating numbers[i] on the right side as the new value

    The right side is evaluated first, so numbers[i] supplies the old value before the assignment replaces the element.

    Fix: Trace the statement as read the old value, multiply it by 2, then write the result to the same index.

  • Choosing value-based iteration when the list must be updated

    Updating an element requires identifying its position so a new value can be written there.

    Fix: Use index-based iteration with range() and len() when elements must change.

  • Skipping intermediate list states

    Without tracing each index, it is easy to lose track of which elements have already changed.

    Fix: Write the list after every assignment and identify the current index at each step.

EASY

Trace an index-based loop that applies numbers[i] = numbers[i] * 2 to the list [4, 5]. Record the list after each update and state the final list.

Hints
  • Identify the current index for the first update.
  • Read the old value at that index before multiplying it.
  • Write the changed list before moving to the next index.

Key Takeaways

  1. range(len(list)) combines the list length with range() to generate indices for an index-based loop.
  2. list[i] can be read on the right side of an assignment and written on the left side of the same assignment.
  3. The statement numbers[i] = numbers[i] * 2 reads the old value and writes the doubled value back to the same position.
  4. Use value-based iteration for reading values and index-based iteration when list elements must be updated.
  5. Tracing each index and intermediate list state reveals the final state of the list.

Key Takeaways

  • Use range(len(list)) to generate indices for iterating through a list by position.
  • An assignment such as numbers[i] = numbers[i] * 2 reads the old element and writes a new value to the same index.
  • Choose value-based iteration for reading and index-based iteration for updating list elements.
  • Trace each iteration and record the list state after every assignment to predict the final result.