19. Nested loops

A loop repeats a block. What if that block holds another loop? That is a nested loop: the inner one runs fully on every round of the outer one. Nested loops build grids, tables, and anything with rows and columns.

A loop inside a loop

Put one for inside another. The inner loop finishes before the outer one moves:

for outer := 1; outer <= 3; outer++ {
    for inner := 1; inner <= 2; inner++ {
        fmt.Println(outer, inner)
    }
}

Output:

1 1
1 2
2 1
2 2
3 1
3 2

Follow the order. While outer is 1, the inner loop runs (1, 2). Then outer becomes 2 and it runs again. That is 3 × 2 = 6 runs.

Give the two loop variables different names. row/col or i/j are common pairs. Using i for both compiles, but the inner i is a new variable that hides the outer one, so inside the inner loop you cannot read the outer count:

for i := 1; i <= 2; i++ {
    for i := 1; i <= 2; i++ {
        fmt.Println("inner", i)
    }
    fmt.Println("outer", i)
}

Output:

inner 1
inner 2
outer 1
inner 1
inner 2
outer 2

Building a row at a time

One value per line rarely suits a grid. The usual trick: the outer loop handles rows; the inner loop builds one string, printed when the row is done. += adds to the string, and strconv.Itoa from Chapter 14 turns each number into text:

for row := 1; row <= 3; row++ {
    line := ""
    for col := 1; col <= 3; col++ {
        line += strconv.Itoa(row*col) + "\t"
    }
    fmt.Println(line)
}

Output (a 3×3 multiplication grid):

1       2       3
2       4       6
3       6       9

Notice line := "" sits inside the outer loop but outside the inner one. It resets each row, fills up in the inner loop, then prints. The "\t" from Chapter 12 puts a tab after each number, which lines up the columns.

Open exercises/19/01-grid.go. It prints a 3×3 grid. Change only the two end values to make it 5×5.

A triangle with a changing inner loop

The inner loop's condition can depend on the outer variable. Run it from 1 to row and you get a triangle:

for row := 1; row <= 4; row++ {
    line := ""
    for star := 1; star <= row; star++ {
        line += "*"
    }
    fmt.Println(line)
}

Output:

*
**
***
****

Row 1 runs the inner loop once; row 4 runs it four times. The shape comes from the maths.

strings.Repeat("*", row) from Chapter 14 would build each row in one call. Writing the loop yourself is the practice here, and many grids have rows that strings.Repeat cannot build, like the multiplication grid above.

How many times does the body run?

Multiply the counts. An outer loop of 10 around an inner loop of 10 runs the body 10 × 10 = 100 times. It grows fast: three loops of 100 each is a million runs. A computer handles a million simple runs quickly, but the count is worth working out before you add another level.

Homework

Homework starters are in exercises/19/homework/. Each one runs as it is and prints a placeholder line.

Problem 1 — Rectangle of hashes

Open exercises/19/homework/01-rectangle.go. With nested loops, print a rectangle of # 5 wide and 3 tall:

#####
#####
#####

Problem 2 — Coordinate pairs

Open exercises/19/homework/02-coords.go. Print every (x, y) pair for x and y from 1 to 3, one per line: (1, 1), (1, 2), and so on. Nine lines.

Problem 3 — Times table

Open exercises/19/homework/03-times-table.go. Print the full multiplication grid from 1×1 to 5×5: five rows of five numbers each, with a tab after each number.

Challenge — Right triangle

Open exercises/19/homework/04-triangle.go. Print a right-angled triangle of * 6 rows tall, where row n has n stars. For a stretch, flip it upside down (6 stars on the first row, 1 on the last).

Stuck or finished? Open the homework solutions page.