Iterating over a list

Loops over items and indexes, totals, counts, min and max, and linear search.

F3.4Strings, lists and recordsGCSE15 min

Covers OCR J277 2.2.3 Additional programming techniques · AQA 8525 3.2.6 Data structures · Edexcel 1CP2 6.2.2 Sequence, selection, repetition and iteration

Do this lesson in the simulator

A list is only useful if you can work through it. This lesson puts together two things you already know, lists and loops, into the most common thing programs do with data: go through every item and do something with it.

for over the items

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

legs = [20, 15, 30, 15]
for length in legs:
    print("driving", length, "cm")
    forward(60, distance=length)
    turn_right(30, angle=90)
print("finished at", position())

Run this in the simulator

for length in legs visits each item in turn, first to last, putting it in length. No range and no index needed when you only want the items. Change the list and the drive changes: the program is now driven by data.

for over the indexes

When you need the position as well as the item, loop over range(len(...)):

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

colours = ["red", "orange", "green"]
for i in range(len(colours)):
    print("step", i, "is", colours[i])
    led(colours[i])
    wait(0.5)

for i, colour in enumerate(colours):
    print(i, colour)

Run this in the simulator

range(len(colours)) gives 0, 1, 2: every valid index. enumerate gives the index and the item together, which is often tidier.

The patterns, over a list

The loop patterns from lesson F2.7 work on any list. Python also has built-in functions for the common ones:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

readings = [41.0, 35.5, 30.2, 25.8, 20.1]

total = 0
for r in readings:
    total = total + r
print("total", total, "or with sum:", sum(readings))
print("average", total / len(readings))

close = 0
for r in readings:
    if r < 30:
        close = close + 1
print(close, "readings under 30 cm")

print("smallest", min(readings), "largest", max(readings))

Run this in the simulator

It is worth being able to write the loop yourself as well as use sum, min and max: exam questions often ask for the algorithm, and a loop can do things the built-ins cannot, such as count only the readings under 30.

The loop visiting each reading in turn, with the running total and the count of readings under 30 after each onertotalclosestarts 0starts 0pass 141.0+41.00pass 235.5+76.50pass 330.2+106.70pass 425.8+132.51under 30: +1pass 520.1+152.62under 30: +1
Each pass adds one reading to the total, so the last total, 152.6, is the sum of all 5. The count only goes up on the passes where r is under 30, the two outlined in green.

Readings from the robot

Collect first, then work through the list:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

readings = []
for step in range(6):
    readings.append(distance())
    forward(50, distance=6)

print("readings:", readings)
biggest_drop = 0
for i in range(1, len(readings)):
    drop = readings[i - 1] - readings[i]
    if drop > biggest_drop:
        biggest_drop = drop
print("biggest change between two readings:", round(biggest_drop, 1), "cm")

Run this in the simulator

The second loop starts at index 1 so that readings[i - 1] always exists. Comparing each item with the one before it is another pattern you will use often.

Six readings in a row, with each one from index 1 on compared with the one before it[0][1][2][3][4][5]readingsi = 1i = 2i = 3i = 4i = 5no i = 0:nothing beforedrop = readings[i - 1] - readings[i]
The loop runs i from 1 to 5, so each curve joins a reading to the one before it: 5 comparisons for 6 readings. Starting at 0 would ask for readings[-1], which is the last reading, not one before the first.

Searching a list

Linear search looks at each item in turn until it finds the one it wants:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

names = ["Ada", "Alan", "Grace", "Tim"]
target = input("Who are you looking for? ")
found = False
for i in range(len(names)):
    if names[i] == target:
        print(target, "is at index", i)
        found = True
        break
if not found:
    print(target, "is not in the list")

Run this in the simulator

The found flag remembers whether the loop succeeded, and break stops looking once it has. Module F5 compares this with faster ways to search.

A linear search for Grace checking Ada, then Alan, then finding Grace at index 2 and stopping before Timlooking for "Grace"0"Ada"no match1"Alan"no match2"Grace"match:found, break3"Tim"never checked3 names looked at out of 4
The search checks one name at a time from index 0. It finds Grace on the third look, and break stops the loop there, so the rest of the list is never read.

Task: sensor log

Drive forward in five steps of 8 cm, recording distance() before each step in a list. Then print four lines: readings: <the list>, smallest: <cm>, largest: <cm> and average: <cm>. Work the average out with a loop or with sum and len, not by typing numbers.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

readings = []

Challenges

  1. Find the smallest reading with a loop, without using min.
  2. Drive a shape from a list of [distance, turn] pairs, such as [[30, 90], [20, 90], [30, 90], [20, 90]].
  3. Count how many names in a list start with the letter A.

Past paper questions on this

Real exam questions that test this, each worked through with a program you can run.