Start learning free

LESSON 192 OF 348 · NESTED LOOPS & BRUTE FORCE

Nested Loops in Kotlin: for Loops Inside for Loops

Lesson Read the full explanation

A nested loop has one loop inside of another. These are typically used for working with two dimensions such as printing stars in rows and columns as shown below. When a loop is nested inside another loop, the inner loop runs many times inside the outer loop. In each iteration of the outer loop, the inner loop will be re-started. The inner loop must finish all of its iterations before the outer loop can continue to its next iteration.

Example:

for (row in 0 until 3) {
    for (col in 0 until 5) {
        print("*")
    }
    println()
}

// This code prints a rectangle with 3 rows and 5 columns, filled with '*'

Iterating through multidimensional arrays

Nested loops are also helpful when we want to iterate through a multi dimensional array, for example:

val arr = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6))

for (i in 0 until arr.size) {
    for (j in 0 until arr[i].size) {
        println(arr[i][j])
    }
}

This outputs each sub-element in arr one at a time. Note that for the inner loop, we are checking the .length of arr[i], since arr[i] is itself an array.

Breaking nested loops

In a nested loop, a break statement only stops the loop it is placed in. Therefore, if a break is placed in the inner loop, the outer loop still continues. For example:

val arr = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6))

for (i in 0 until arr.size) {
    for (j in 0 until arr[i].size) {
        if (arr[i][j] == 3) {
            break
        }
        println(arr[i][j])
    }
}

// prints the numbers 1, 2, 5 and 6 on different lines

When i is 1 and j is 0, we execute the break. This means we stop the inner loop and go back to the outer loop to continue from the next iteration, which is i = 2. And as you can see, we print all the elements of row 2.

However, if the break is placed in the outer loop, all of the looping stops. For example:

val arr = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6))

for (i in 0 until arr.size) {
    if (arr[i][0] == 3) {
        break
    }
    for (j in 0 until arr[i].size) {
        println(arr[i][j])
    }
}
// prints the numbers 1 and 2 on different lines

Assignment
Follow the Coding Tutorial and let's write some nested loops.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 4
    Ctrl + Enter to check

    KOTLIN · NESTED LOOPS & BRUTE FORCE

    Nested Loops in Kotlin, explained

    What a nested loop is

    A nested loop is a loop placed inside the body of another loop. The outer loop starts one pass, and the inner loop then runs from beginning to end. Only when the inner loop has finished does the outer loop move on to its next pass, and then the inner loop starts again from scratch.

    If the outer loop runs 5 times and the inner loop runs 10 times per pass, the inner body runs 5 × 10 = 50 times in total. Nested loops are how you work with two dimensions: rows and columns, grids, tables, and every pair of items in a collection.

    The exercise: a rectangle of stars

    The task is to print a rectangle of stars with 5 rows and 10 columns:

    **********
    **********
    **********
    **********
    **********

    The outer loop handles the rows, and the inner loop handles the columns of one row.

    Step by step

    1. Loop over the rows. Write for (row in 0 until 5). The range 0 until 5 excludes its end, so row takes the values 0, 1, 2, 3 and 4: five passes.
    2. Loop over the columns inside it. Write for (col in 0 until 10) in the body of the first loop. It gives ten passes for every row.
    3. Print one star without a newline. In the inner loop, print("*") writes the star and stays on the same line. println would end the line after every star and give a column of 50 stars.
    4. End the row. After the inner loop's closing brace, but still inside the outer loop, call println() with no argument. It only moves to the next line. Placed inside the inner loop, it would break every row into single stars.

    The solution in Kotlin

    for (row in 0 until 5) {
        for (col in 0 until 10) {
            print("*")
        }
        println()
    }
    

    Some Kotlin details about these lines:

    • Ranges. 0 until 5 stops before 5. The range 1..5 includes both ends. Choose whichever matches the number you need. For a count of 5 starting from zero, until is the natural fit.
    • The loop variables are read-only. You can't assign to row or col inside the body. Each pass gets a fresh value.
    • Unused variable. The inner loop never uses col. It exists only to count the passes. Kotlin warns about an unused variable but compiles; naming it _ is allowed and tells readers it is unused.
    • Scope. row is visible inside the inner loop, so you can use it there. col disappears when the inner loop ends.

    Using both counters

    The loop variables are most useful when the inner loop uses them. A multiplication table prints i * j for each pair:

    for (i in 1..3) {
        for (j in 1..3) {
            print("${i * j}\t")
        }
        println()
    }
    

    The output has three rows:

    1	2	3	
    2	4	6	
    3	6	9	

    When the inner range depends on the outer variable, the shape changes. With for (j in 1..i) as the inner loop, row i gets i stars, which makes a triangle with 1, 2, 3 and then 4 stars on successive rows when i runs from 1 to 4.

    Looping over a two-dimensional array

    An array of arrays is a grid. In Kotlin, arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6)) holds three rows of two numbers. The outer loop goes through the rows, and the inner loop goes through the numbers of the current row:

    val grid = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4), intArrayOf(5, 6))
    
    for (i in grid.indices) {
        for (j in grid[i].indices) {
            print(grid[i][j])
        }
        println()
    }
    

    This prints 12, 34 and 56 on separate lines. A Kotlin array reports its length with .size, not .length, and .indices is the range of valid positions, 0 until size. The inner loop uses the size of grid[i], because each row is itself an array. When you don't need the positions, loop over the values directly: for (row in grid) for (v in row) print("$v ").

    Break in nested loops

    A break leaves only the loop that directly contains it. Inside the inner loop, it ends that inner loop, and the outer loop continues:

    for (i in grid.indices) {
        for (j in grid[i].indices) {
            if (grid[i][j] == 3) break
            println(grid[i][j])
        }
    }
    

    This prints 1, 2, 5 and 6, each on its own line. The 3 stops the second row early, so the 4 is skipped, but the third row still runs. To leave both loops at once, put a label on the outer loop and break to it:

    outer@ for (i in grid.indices) {
        for (j in grid[i].indices) {
            if (grid[i][j] == 3) break@outer
            println(grid[i][j])
        }
    }
    

    This prints only 1 and 2. A break written in the outer loop's own body, outside the inner loop, also stops everything, because there is nothing else it can leave.

    Common mistakes

    • Putting println() in the wrong place. Inside the inner loop it prints each star on its own line. After the outer loop it prints a single line of 50 stars.
    • Using println("*") for the stars. The rectangle needs print so that the stars of a row stay together.
    • Off-by-one ranges. 0 until 5 gives 5 passes, while 0..5 gives 6.
    • Swapping rows and columns. The outer loop is the 5 rows and the inner loop is the 10 columns. Swapped, you get 10 rows of 5 stars.
    • Using .length. Kotlin arrays use .size; .length doesn't compile.
    • Expecting break to leave both loops. Without a label it leaves only the innermost one.

    Key takeaways

    • The inner loop runs completely for every pass of the outer loop, so the body runs outer × inner times.
    • Use print inside the inner loop and println() after it to build rows.
    • A grid is an array of arrays, walked with one loop inside another.
    • break affects the innermost loop only, unless you break to a label.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free