← Teacher guide

Totals and the biggest

Students total a column, divide for an average and track the longest song with a biggest-so-far variable, then restrict the average to one genre, find the oldest song and write genre stats that cope with no matches.

Data detective · Reading data · about 50 minutes · Open the student lesson

Classroom resources

Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.

Students will be able to

Timing

Predict and Run 10 min · Investigate 15 min · Modify 15 min · Make 10 min

Before class

Read the unit primer first. Two patterns carry the lesson. The accumulator: total = 0 before the loop, total = total + x inside it (the bug task replaces instead of adding). The biggest so far: start with the first row, and replace it only when a row beats it. float() turns "3.9" into a number (minutes have decimals; years use int()). An average of some rows needs its own count, since len(songs) counts every song; with no matching rows the count is 0 and dividing by it is an error, which the Make asks students to handle. round(x, 1) is used once for tidy output.

Running the lesson

  1. Predict: write total on the board and update it aloud for each number.
  2. Investigate: do the trace together, then ask why Billie Jean does not replace Bohemian Rhapsody.
  3. Modify: ask where the count must go up: inside the if, beside the adding.
  4. Make: ask students for a genre that is not in the data, and what their program does with it.

The hard part (on purpose)

The biggest-so-far pattern. Ask students to fill in the trace by hand before running anything; resist writing the comparison for them.

When students get stuck

What you will seeA question to askThe fix
The total is only the last song's minutes.Does the line add to total, or replace it?total = total + minutes.
ZeroDivisionError: division by zero.What is the count when no song matches?Check if count == 0 before dividing, and print a message instead.
TypeError: can only concatenate str (not "float") to str.Is the number being joined onto text?Wrap it in str() before joining with +.

Answers to the checks

  1. Predict: What does it print?
    4.0. total goes 3, then 7, then 12, and 12 / 3 is 4.0. Dividing with / always gives a decimal number.
  2. Follow the loop: The first three songs are Jolene (2.7), Bohemian Rhapsody (5.9) and Billie Jean (4.9). Fill in total and the longest minutes after each one.
    8.6, 5.9, 13.5, 5.9
    total grows with every song. longest changes only when a song is longer than the one it holds, so Billie Jean (4.9) does not replace Bohemian Rhapsody (5.9).
  3. Where longest starts: Why does longest start as songs[0], not 0?
    It holds a whole song (a dictionary), so it starts as a real song: the first one
    longest is a song, so the program can print its title at the end. Starting with the first song means there is always something to compare with.
  4. Spot the bug: This should add up the minutes of every song, but it prints only 3.3, the length of the last song. Click the line that is wrong.
    line 8
    total = float(...) replaces the total each time. total = total + float(...) adds each song on.
  5. Where this leads: A spreadsheet's AVERAGE() and MAX() give the same answers. Why learn the loop?
    The loop works for any question, such as the longest pop song after 2010, not only the ones a button exists for
    Built-in tools answer common questions. A loop with your own if answers any question, and it is how those built-in tools work inside.

Solutions

One possible solution for each task. Other correct programs are fine.

Modify › Average rock song

import csv

with open("music.csv") as f:
    songs = list(csv.DictReader(f))

total = 0
count = 0
longest = songs[0]
for song in songs:
    if song["genre"] == "rock":
        minutes = float(song["minutes"])
        total = total + minutes
        count = count + 1
    if float(song["minutes"]) > float(longest["minutes"]):
        longest = song

print("Average rock song: " + str(round(total / count, 1)) + " minutes")
print("Longest: " + longest["title"] + " (" + longest["minutes"] + " minutes)")

Modify › The oldest song

import csv

with open("music.csv") as f:
    songs = list(csv.DictReader(f))

total = 0
longest = songs[0]
oldest = songs[0]
for song in songs:
    minutes = float(song["minutes"])
    total = total + minutes
    if minutes > float(longest["minutes"]):
        longest = song
    if int(song["year"]) < int(oldest["year"]):
        oldest = song

print("Average length: " + str(round(total / len(songs), 1)) + " minutes")
print("Longest: " + longest["title"] + " (" + longest["minutes"] + " minutes)")
print("Oldest: " + oldest["title"] + " (" + oldest["year"] + ")")

genre stats

import csv

with open("music.csv") as f:
    songs = list(csv.DictReader(f))

genre = input("Which genre? ").strip().lower()
matches = []
for song in songs:
    if song["genre"].lower() == genre:
        matches.append(song)

if len(matches) == 0:
    print("No songs in that genre.")
else:
    total = 0
    shortest = matches[0]
    for song in matches:
        minutes = float(song["minutes"])
        total = total + minutes
        if minutes < float(shortest["minutes"]):
            shortest = song
    print(str(len(matches)) + " songs, " + str(round(total / len(matches), 1)) + " minutes on average")
    print("Shortest: " + shortest["title"] + " (" + shortest["minutes"] + " minutes)")

Stretch and support

Stretch: Find the longest song of each decade (the 1980s, the 1990s...), using year // 10 * 10 for the decade.

Support: Give students the rock average with the count already added, and ask them to do the oldest song by copying the longest pattern.

Exit ticket

Why does an average of the pop songs need its own count?

len(songs) counts every song; the average of some songs divides their total by how many of them there are, counted inside the if.

What each step is for

Where it leads

Next lesson counts every genre at once with a dictionary and draws a bar chart. In pandas (Lesson 5) these become one-word methods such as .mean() and .max().