Skip to content
wannacode

Tables of numbers

Problem

Three weeks, three lists

A coffee shop records how many coffees it sold each workday. For one week, the list from the last lesson is exactly what you need. For three weeks you make three lists:

week1 = [42, 38, 51, 47, 60]
week2 = [45, 40, 49, 52, 63]
week3 = [39, 44, 50, 48, 58]
tuesday = week1[1] + week2[1] + week3[1]
print(f"Tuesday: {tuesday}")
Output
Tuesday: 122

Now the manager asks how much was sold on all the Tuesdays of the past year. That is 52 weeks, so 52 lists and a sum with 52 terms. And a loop cannot go through week1, week2, week3: those are different names, not indexes.

The data is a table: the weeks are rows, the days are columns. You need a list that is a table.

The idea

A list of lists: row and column

A table in Python is a list of lists: each element of the outer list is a whole row, and a row is a regular list of numbers. In Java and C# this is called a two-dimensional array, and often a matrix.

sales = [
[42, 38, 51, 47, 60],
[45, 40, 49, 52, 63],
[39, 44, 50, 48, 58],
]
print(sales[1][0])
print(f"{len(sales)} weeks, {len(sales[0])} days")
Output
45
3 weeks, 5 days
  • Each inner [ … ] is one row. We write them one under the other, so the table is easy to see.
  • sales[1][0] is the row with index 1 (the second week) and the column with index 0 (Monday). The row comes first, then the column. Counting starts at 0 here too.
  • len(sales) is the count of rows. len(sales[0]) is the length of the first row, that is, the count of columns.

sales[1] is a whole row, a regular list with 5 numbers. That is why you write two separate brackets [1][0]: first you get the row, then the number in it.

sales = [
[42, 38, 51, 47, 60],
[45, 40, 49, 52, 63],
[39, 44, 50, 48, 58],
]
print(sales[1])
print(sales)
Output
[45, 40, 49, 52, 63]
[[42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58]]

You make an empty 52 × 5 table full of zeros row by row: 52 times you add a new row of 5 zeros.

table = []
for week in range(52):
table.append([0] * 5)
table[0][1] = 7
print(len(table), len(table[0]), table[0][1], table[1][1])
Output
52 5 7 0
More precisely, if you are curious
  • Since the rows are separate lists, they can have different lengths. Such a table is called jagged:
shifts = [
[8, 8],
[6, 6, 6],
[12],
]
print(len(shifts[1]), len(shifts[2]))
Output
3 1

In it, len(sales[0]) is not the length of every row. That is why in a nested loop it is safer to write len(sales[row]): the length of the row you are going through right now.

  • Don't make the empty table with [[0] * 5] * 3. That way all three places point to one and the same row, like the two names of one list from the last lesson. A change in one row shows in all of them:
table = [[0] * 5] * 3
table[0][1] = 7
print(table)
Output
[[0, 7, 0, 0, 0], [0, 7, 0, 0, 0], [0, 7, 0, 0, 0]]

See it

The whole table on the screen

To go through every cell, you need two loops, one inside the other. You already know nested loops from the stars: the outer one picks the row, the inner one goes through the columns of that row.

for week in range(len(sales)):
for day in range(len(sales[0])):
print(f"{sales[week][day]:5}", end="")
print()
Output
42 38 51 47 60
45 40 49 52 63
39 44 50 48 58

The outer loop runs 3 times, once for each week. On each of its rounds the inner one runs 5 times. 15 cells in total, in the order you read a table: left to right, top to bottom.

:5 in the f-string prints the number in a field 5 characters wide, aligned to the right. That way the columns line up one under the other. end="" keeps the numbers on one line, and the empty print() after each row moves to a new one.

Try it

Which cell?

In the grade book each row is a student, and each column is a subject.

What will the program print?

grades = [
[5, 3, 4, 6],
[3, 4, 6, 5],
[6, 2, 5, 4],
]
print(grades[1][2])
Answer

The idea

Sums by rows and by columns

How many coffees were sold each week? That is the sum of each row. The sum starts at 0 for each new row, so total is inside the outer loop:

for week in range(len(sales)):
total = 0
for day in range(len(sales[0])):
total += sales[week][day]
print(f"Week {week + 1}: {total}")
Output
Week 1: 238
Week 2: 249
Week 3: 239

sales = [
[42, 38, 51, 47, 60],
[45, 40, 49, 52, 63],
[39, 44, 50, 48, 58],
]
for week in range(len(sales)):
total = 0
for day in range(len(sales[0])):
total += sales[week][day]
print(f"Week {week + 1}: {total}")
Step by step, in words
  1. The table: 3 weeks (rows) of 5 days (columns).
  2. week = 0: total starts over, from 0.
  3. The inner loop goes through the days: 42 + 38 + 51 + 47 + 60 = 238.
  4. It prints "Week 1: 238".
  5. week = 1: total starts over, from 0.
  6. The inner loop goes through the days: 45 + 40 + 49 + 52 + 63 = 249.
  7. It prints "Week 2: 249".
  8. week = 2: total starts over, from 0.
  9. The inner loop goes through the days: 39 + 44 + 50 + 48 + 58 = 239.
  10. It prints "Week 3: 239".

How much was sold on Monday, on Tuesday, and so on? That is the sum of each column. The table is the same, only the order of the loops changes: the day is on the outside, the weeks are on the inside. You will finish it on the next card.

Which loop is on the outside decides what you add up. The indexes in sales[week][day] don't move: the row always comes first.

Try it

Sum by days

The outer loop goes through the days, the inner one through the weeks. What goes in the blank?

days = ["Mon", "Tue", "Wed", "Thu", "Fri"]
for day in range(len(sales[0])):
    total = 0
    for week in range(len(sales)):
        total += sales[][day]
    print(f"{days[day]}: {total}")

Try it

Find the bug

The hall has 3 rows of 5 seats: 1 is taken, 0 is free. There are 7 free seats, but the program says 5. Which line has the bug?

Pick the line with the bug.

The idea

Booking: people count from 1

A moviegoer wants row 3, seat 2. For them the first row is row 1. For the list it is row 0. That is why you subtract 1 from the numbers a person types before you use them as indexes:

row = int(input())
seat = int(input())
if hall[row - 1][seat - 1] == 1:
print("The seat is taken.")
else:
hall[row - 1][seat - 1] = 1
print(f"Booked: row {row}, seat {seat}")
Input
3
2
Output
Booked: row 3, seat 2
Input
1
2
Output
The seat is taken.

hall is the hall from the previous card. You change a cell like a regular variable: hall[row - 1][seat - 1] = 1.

More precisely, if you are curious
  • If someone asks for row 7, index 6 is outside the table and the program stops with IndexError, just like with a regular list. It is trickier if they ask for row 0: the index is -1, and in Python that is the last row. There is no error, and the wrong seat gets booked:
hall = [
[1, 1, 0, 0, 1],
[0, 1, 1, 1, 0],
[0, 0, 0, 1, 1],
]
try:
print(hall[7 - 1][2 - 1])
except IndexError as error:
print(f"IndexError: {error}")
print(hall[0 - 1])
Output
IndexError: list index out of range
[0, 0, 0, 1, 1]

So check the numbers before you use them: 1 <= row <= len(hall), and the same for the seat.

  • Here each number is on its own line. How to read a whole line of numbers at once (0 1 1 0), you will see in the next lesson, on text.

Exercise

Working with a table

Solve the exercises in your editor. Write the tables straight into the code.

1. Diagonals and rows. For the 2 × 2 table below, find the sum along the main diagonal (from top left down to bottom right), along the other diagonal, and the sums of the first and the second row. On the main diagonal the row index and the column index are equal. On the other diagonal the column is n - 1 - row.

The table
1 2
3 4
Output
Main diagonal: 5
Other diagonal: 5
First row: 3
Second row: 7

2. Flip the table. The sales are recorded by weeks (rows) and days (columns). Accounting wants them by days and weeks. Make a new table in which the rows become columns. This is called transposing. The new table has the size columns × rows, and cell [r][c] goes to [c][r].

The table
42 38 51
45 40 49
Output
42 45
38 40
51 49

Exercise

Mazes and treasure

3. How many paths are there? The maze is a table: 0 is a passage, 1 is a wall. You start from the top left corner and get to the bottom right one, moving only right or down. How many different paths are there?

The maze
0 0 0 0
0 1 0 0
0 0 0 1
1 0 0 0
Output
Paths: 3
Hint

Make a second table ways with the same size. In it, write how many ways there are to reach each cell. There is 1 way to reach the start. There are 0 ways to reach a wall. Every other cell is reached either from above or from the left, so the count is the sum of the cell above it and the cell to its left (if they exist). Fill in the table row by row, from top to bottom. The answer is in the last cell.

4. The shortest path. A hard one. Now you can move in all four directions: up, down, left and right. What is the smallest number of steps to get from the top left to the bottom right corner? If there is no path, print "No path".

The maze
0 0 0 0 0
1 1 1 1 0
0 0 0 0 0
0 1 1 1 1
0 0 0 0 0
Output
Shortest path: 16 steps
Hint

Send out a "wave" from the start. Make a table dist full of -1 (we haven't reached that cell yet), and put 0 at the start. Then repeat: find all the cells whose dist equals the current step, and for their free neighbors that we haven't reached yet, write step + 1. The wave grows by one step on every round. Stop when it reaches the goal or when nothing has changed (then there is no path). The four directions are handy as two lists: dr = [-1, 1, 0, 0] and dc = [0, 0, -1, 1]. The neighbor in direction k is at row r + dr[k] and column c + dc[k].

More exercises

  • Find the treasure. A game on a map that is a table: 0 is a path, 1 is an obstacle, 2 is the treasure. The player starts in the top left corner. On each move, print the map (P for the player, # for an obstacle, . for a path) and read a command as a number: 8 up, 2 down, 4 left, 6 right (as on the number pad). If the move leads off the map or into an obstacle, the player stays in place. When they step on the treasure, print "You found the treasure in … moves!".
  • The row with the most sales. For the table sales, find which week was the strongest and which day of the week is the strongest on average.
  • Free seats in a row. For the hall hall, find a row that has at least 3 free seats next to each other, and print the number of the row and of the first seat.

Test

Check yourself

1. What is sales[1] in the sales table?
2. The table sales has 3 weeks (rows) and 5 days (columns). What does len(sales[0]) give?
3. Which is the last cell of a table with 3 rows and 5 columns?
4. You want the sum of one column (one day across all the weeks). Which index changes in the inner loop?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·