Skip to content
ExamSpine

Lesson 5.13

Two-dimensional lists: rows and columns

Part 5: Text, lists, stacks and queuesReading, about 7 min3 exercises in this lesson

Java answers can't run on Spine yet. You can still read Java, trace it, and put an answer's lines in order.

Rows and columns

By the end of this you will be able to make a grid of values, read and change one cell by its row and column, and visit every cell, one row or one column at a time.

Some data has two directions. A game has players and rounds. A cinema has rows of seats, and seats along each row. You could keep this in one long list, but then you would have to work out where each row starts. A grid keeps the shape.

A list of rows

Here two players each play three rounds. Each row holds one player's points, and each column is one round.

round 0round 1round 2
player 0352
player 1416
points = [[3, 5, 2], [4, 1, 6]]
print(points[1][2])
print(points[0][1])
public static void main(String[] args) {
    int[][] points = {{3, 5, 2}, {4, 1, 6}};
    System.out.println(points[1][2]);
    System.out.println(points[0][1]);
}

When it runs:

6
5

In Python, a grid is a list whose values are lists: a list of rows. In Java, it is a two-dimensional array. The type int[][] means an array whose values are arrays of int, and the literal has one pair of curly brackets around each row, inside one pair around the whole grid.

To reach one cell, give two indexes: the row first, then the column. points[1][2] means row 1, column 2, which holds 6. Both indexes start at 0, as they do in any list.

It helps to read it in two steps. points[1] is the whole of row 1, the list of 4, 1 and 6. Then [2] picks the value at index 2 of that row.

You change a cell the same way. points[0][1] = 9 replaces the 5 in row 0, column 1 with 9, and leaves every other cell alone.

How many rows and columns

points = [[3, 5, 2], [4, 1, 6]]
print(len(points))
print(len(points[0]))
public static void main(String[] args) {
    int[][] points = {{3, 5, 2}, {4, 1, 6}};
    System.out.println(points.length);
    System.out.println(points[0].length);
}

When it runs:

2
3

The length of the grid itself is the number of rows, because the grid is a list of rows. The length of one row is the number of columns. In Python these are len(points) and len(points[0]). In Java they are points.length and points[0].length. In this lesson every row has the same length, so row 0 tells you the number of columns for all of them.

Making a grid of zeros

grid = []
for r in range(2):
    grid.append([0] * 3)
grid[1][0] = 7
print(grid)
import java.util.Arrays;

public static void main(String[] args) {
    int[][] grid = new int[2][3];
    grid[1][0] = 7;
    System.out.println(
        Arrays.deepToString(grid));
}

When it runs:

[[0, 0, 0], [7, 0, 0]]

In Java, new int[2][3] makes 2 rows of 3 columns, and Java puts 0 in every cell. The number of rows comes first, just as the row index does.

In Python, the loop adds a new row of three zeros on each pass. Do not write [[0] * 3] * 2 instead. That makes a list that holds the same row twice, not two rows, so changing grid[1][0] to 7 changes row 0 as well, and the grid prints as [[7, 0, 0], [7, 0, 0]].

Printing works differently in the two languages. Python's print(grid) shows the rows inside square brackets, as above. Java's System.out.println(grid) does not show the values: it prints [[I@ and then a code made of letters and digits. To see the values, use Arrays.deepToString(grid), with import java.util.Arrays; at the top of the file, or print the cells yourself with a loop.

Visiting every cell

To visit every cell, use a nested loop: an outer loop over the rows, and inside it a loop over the columns.

points = [[3, 5, 2], [4, 1, 6]]
total = 0
for row in range(len(points)):
    for col in range(len(points[0])):
        total = total + points[row][col]
print(total)
public static void main(String[] args) {
    int[][] points = {{3, 5, 2}, {4, 1, 6}};
    int total = 0;
    for (int row = 0; row < points.length;
            row++) {
        for (int col = 0;
                col < points[0].length;
                col++) {
            total = total + points[row][col];
        }
    }
    System.out.println(total);
}

When it runs, it prints 21, the points of both players in every round.

The cells are visited in this order: row 0, column 0; row 0, column 1; row 0, column 2; then row 1, columns 0, 1 and 2. The inner loop runs all the way through for each row, so the add line runs 2 times 3 = 6 times, once for each cell.

One row, or one column

The total of one row keeps the row fixed and moves along the columns. The total of one column keeps the column fixed and moves down the rows.

points = [[3, 5, 2], [4, 1, 6]]
row_total = 0
for col in range(len(points[0])):
    row_total = row_total + points[1][col]
print(row_total)
col_total = 0
for row in range(len(points)):
    col_total = col_total + points[row][2]
print(col_total)
public static void main(String[] args) {
    int[][] points = {{3, 5, 2}, {4, 1, 6}};
    int rowTotal = 0;
    for (int col = 0; col < points[0].length;
            col++) {
        rowTotal = rowTotal + points[1][col];
    }
    System.out.println(rowTotal);
    int colTotal = 0;
    for (int row = 0; row < points.length;
            row++) {
        colTotal = colTotal + points[row][2];
    }
    System.out.println(colTotal);
}

When it runs:

11
8

11 is player 1's total over the three rounds: 4 + 1 + 6. 8 is the total of round 2 for both players: 2 + 6.

Notice which length each loop uses. Moving along a row, the index goes through the columns, so it stops at the number of columns. Moving down a column, the index goes through the rows, so it stops at the number of rows.

Every row's total, or every column's

Put the one-column loop inside a loop over the columns, and you get each column's total in turn. Start the total at 0 inside the outer loop, so each column starts again from nothing.

points = [[3, 5, 2], [4, 1, 6]]
for col in range(len(points[0])):
    total = 0
    for row in range(len(points)):
        total = total + points[row][col]
    print(total)
public static void main(String[] args) {
    int[][] points = {{3, 5, 2}, {4, 1, 6}};
    for (int col = 0; col < points[0].length;
            col++) {
        int total = 0;
        for (int row = 0; row < points.length;
                row++) {
            total = total + points[row][col];
        }
        System.out.println(total);
    }
}

This one goes by column: the outer loop is over the columns and the inner loop is over the rows. When it runs:

7
6
8

These are the totals of rounds 0, 1 and 2. Swap the two loops, with the rows outside and the columns inside, and the same idea gives each player's total instead: 10, then 11.

Two common mistakes

  • The indexes the wrong way round. The row index always comes first, whichever loop is on the outside. In the program above, writing points[col][row] would ask for row 2, and this grid has only rows 0 and 1, so the program prints two wrong totals and then stops with an index error.
  • The wrong length. A loop over the columns must stop at the length of a row, not the length of the grid. Here, len(points) (or points.length) is 2, so a column loop that uses it never reaches column 2, and no error tells you so.

Now try it yourself on the questions below.

Exercise 5.13.15.13.1 · Write itDown the diagonal

A board game is played on a square grid of whole numbers. Write a function that returns the total of the cells on the diagonal that runs from the top left corner to the bottom right corner. In Python the grid is a list of rows; in Java it is an int[][].

  1. The diagonal is the cell in row 0, column 0, then row 1, column 1, and so on to the last row and column.
  2. The grid is square: it has as many rows as columns, and at least one of each.
  3. The values can be negative. Every value is between -1000 and 1000, and the grid has at most 20 rows.

Only the number your function returns is checked.

def diagonal_total(grid: list[list[int]]) -> int

Examples

Your function is tested on 9 cases: the 4 examples below, and 5 hidden ones that check the rules above.

  • diagonal_total([[2, 5], [7, 3]]) should return 5: 2 in row 0, column 0, plus 3 in row 1, column 1
  • diagonal_total([[6]]) should return 6: one cell is the whole diagonal (rule 2)
  • diagonal_total([[1, 0, 4], [2, 5, 8], [3, 9, 7]]) should return 13: a 3 by 3 grid: 1 + 5 + 7
  • diagonal_total([[-3, 2], [4, -1]]) should return -4: negative values on the diagonal (rule 3)

public static int diagonalTotal(int[][] grid)

Checking whether Java answers can run here.

Examples

Your function is tested on 9 cases: the 4 examples below, and 5 hidden ones that check the rules above.

  • diagonalTotal(new int[][]{new int[]{2, 5}, new int[]{7, 3}}) should return 5: 2 in row 0, column 0, plus 3 in row 1, column 1
  • diagonalTotal(new int[][]{new int[]{6}}) should return 6: one cell is the whole diagonal (rule 2)
  • diagonalTotal(new int[][]{new int[]{1, 0, 4}, new int[]{2, 5, 8}, new int[]{3, 9, 7}}) should return 13: a 3 by 3 grid: 1 + 5 + 7
  • diagonalTotal(new int[][]{new int[]{-3, 2}, new int[]{4, -1}}) should return -4: negative values on the diagonal (rule 3)
solution.pySolution.java

Exercise 5.13.25.13.2 · Write itQuestions everyone got right

A quiz is marked in a grid. Each row is one student, and each column is one question. A cell holds 1 if that student got that question right, and 0 if not. In Python the grid is a list of rows; in Java it is an int[][].

Write a function that returns how many questions every student got right.

  1. A question counts only if its column has a 1 in every row.
  2. There is at least one student and at least one question, and every row has the same length.
  3. The number of students and the number of questions can be different.
  4. Every cell is 0 or 1.

Only the number your function returns is checked.

def questions_all_right(answers: list[list[int]]) -> int

Examples

Your function is tested on 11 cases: the 5 examples below, and 6 hidden ones that check the rules above.

  • questions_all_right([[1, 1, 0], [1, 0, 0]]) should return 1: 2 students, 3 questions: only question 0 has a 1 in every row
  • questions_all_right([[0, 1], [1, 1], [1, 1]]) should return 1: 3 students, 2 questions: question 0 has a 0, question 1 counts (rule 1)
  • questions_all_right([[1]]) should return 1: one student and one question (rule 2)
  • questions_all_right([[0, 0], [0, 0]]) should return 0: no question counts
  • questions_all_right([[1, 1, 1, 1]]) should return 4: one student who got all 4 questions right (rule 3)

public static int questionsAllRight(int[][] answers)

Checking whether Java answers can run here.

Examples

Your function is tested on 11 cases: the 5 examples below, and 6 hidden ones that check the rules above.

  • questionsAllRight(new int[][]{new int[]{1, 1, 0}, new int[]{1, 0, 0}}) should return 1: 2 students, 3 questions: only question 0 has a 1 in every row
  • questionsAllRight(new int[][]{new int[]{0, 1}, new int[]{1, 1}, new int[]{1, 1}}) should return 1: 3 students, 2 questions: question 0 has a 0, question 1 counts (rule 1)
  • questionsAllRight(new int[][]{new int[]{1}}) should return 1: one student and one question (rule 2)
  • questionsAllRight(new int[][]{new int[]{0, 0}, new int[]{0, 0}}) should return 0: no question counts
  • questionsAllRight(new int[][]{new int[]{1, 1, 1, 1}}) should return 4: one student who got all 4 questions right (rule 3)
solution.pySolution.java

Exercise 5.13.3 · Trace itTrace: column totals

Complete the trace table for this Python code. grid has 3 rows of 2 values, and grid[r][c] is the value in row r, column c. The outer loop goes along the columns and the inner loop goes down the rows. Then answer the question below the table. [3]

Line 1: grid = [[4, 7], [9, 3], [6, 8]]
Line 2: for c in range(len(grid[0])):
Line 3, indented 1 level: total = 0
Line 4, indented 1 level: for r in range(len(grid)):
Line 5, indented 2 levels: total = total + grid[r][c]

Fill in one row each time a line changes c, r or total. The table already has the right number of rows. In each row, write only what that line changes; you can leave the other cells empty or copy their values down. Write values the way Python shows them: 3 and 3.0 are different, and text goes in quotes.

Rowcrtotal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Exercise 5.13.3 · Trace itTrace: column totals (Java)

Complete the trace table for this Java code. grid has 3 rows of 2 values, and grid[r][c] is the value in row r, column c. The outer loop goes along the columns and the inner loop goes down the rows. Then answer the question below the table. [3]

Line 1: int[][] grid = {{4, 7}, {9, 3}, {6, 8}};
Line 2: for (int c = 0; c < grid[0].length; c++) {
Line 3, indented 1 level: int total = 0;
Line 4, indented 1 level: for (int r = 0; r < grid.length; r++) {
Line 5, indented 2 levels: total = total + grid[r][c];
Line 6, indented 1 level: }
Line 7: }

Fill in one row each time a line changes c, r or total. The table already has the right number of rows. In each row, write only what that line changes; you can leave the other cells empty or copy their values down. Write values the way Java shows them: 3 and 3.0 are different, and text goes in quotes.

Rowcrtotal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19