Start learning free

LESSON 192 OF 348 · NESTED LOOPS & BRUTE FORCE

Nested Loops in TypeScript: Rows, Columns and break

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(let row = 0; row < 3; row++) {
	for(let col = 0; col < 5; col++) {
		process.stdout.write("*");
	}
    process.stdout.write('\n');
}

// This code prints a rectangle with 3 rows and 5 columns, filled with '*'
// We use process.stdout.write because console.log prints with a trailing newline

Iterating through multidimensional arrays

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

const arr = [
	[1, 2], [3, 4], [5, 6]
];

for (let i = 0; i < arr.length; i++) {
	for (let j = 0; j < arr[i].length; j++) {
		console.log(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:

const arr = [
	[1, 2], [3, 4], [5, 6]
];

for (let i = 0; i < arr.length; i++) {
	for (let j = 0; j < arr[i].length; j++) {
		if(arr[i][j] == 3) {
			break;
		}
		console.log(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:

const arr = [
	[1, 2], [3, 4], [5, 6]
];

for (let i = 0; i < arr.length; i++) {
	if(arr[i][0] == 3) {
		break;
	}
	for (let j = 0; j < arr[i].length; j++) {
		console.log(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

    TYPESCRIPT · NESTED LOOPS & BRUTE FORCE

    Nested Loops in TypeScript, explained

    What a nested loop is

    A nested loop is a loop written inside the body of another loop. The outer loop starts a pass, the inner loop runs through all of its passes, and only when the inner loop is finished does the outer loop move on to its next pass. Each time the outer loop starts a new pass, the inner loop starts again from the beginning.

    If the outer loop runs 5 times and the inner loop runs 10 times for each of them, the inner body runs 5 × 10 = 50 times. This multiplication is the main thing to remember about nested loops, and it is why they matter for performance later in the course.

    Nested loops are the natural tool whenever data has two dimensions: rows and columns, a grid, a table, or every pair of elements in a list.

    The lesson's exercise: a rectangle of stars

    The task is to print a rectangle of 5 rows and 10 columns made of * characters. The outer loop counts rows and the inner loop counts the stars within one row.

    1. Write the outer loop. for (let row = 0; row < 5; row++) runs once per row. The body never reads row; it only counts the passes.
    2. Write the inner loop inside it. for (let col = 0; col < 10; col++) runs once per column of the current row.
    3. Print one star per pass of the inner loop with process.stdout.write("*"). This call prints exactly the text you give it, with nothing added, so the 10 stars of a row land on the same line.
    4. End the row. After the inner loop, still inside the outer loop, print a newline with process.stdout.write("\n"). The next row then starts on a new line.
    for (let row = 0; row < 5; row++) {
        for (let col = 0; col < 10; col++) {
            process.stdout.write("*");
        }
        process.stdout.write("\n");
    }

    The output:

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

    Why not console.log("*")? It always ends its output with a newline, so every star would be alone on its own line. process.stdout.write leaves that decision to you, which is what makes it possible to build a line in pieces. The position of the newline matters too. If you put it inside the inner loop, you get 50 lines with one star each. After the inner loop but outside the outer one, you get one line of 50 stars and a single newline at the end.

    Using the row number

    The inner loop can depend on the outer loop's variable. This version prints a triangle, because row row gets row stars:

    for (let row = 1; row <= 4; row++) {
        for (let col = 0; col < row; col++) {
            process.stdout.write("*");
        }
        process.stdout.write("\n");
    }
    *
    **
    ***
    ****

    Here the inner loop doesn't always run the same number of times: 1, then 2, then 3, then 4. The total is no longer a simple product, but the structure is the same.

    Looping over a two-dimensional array

    A two-dimensional array is an array whose elements are arrays. Its type is written number[][]. The outer loop picks a row, and the inner loop walks along that row:

    const arr: number[][] = [
        [1, 2], [3, 4], [5, 6]
    ];
    
    let total = 0;
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr[i].length; j++) {
            total += arr[i][j];
        }
    }
    console.log(total);
    21

    Notice the inner loop's bound: arr[i].length, not arr.length. The element arr[i] is itself an array, and the rows of a TypeScript array of arrays are allowed to have different lengths, so each row gets asked for its own.

    break only leaves one loop

    A break stops the innermost loop that contains it. Placed in the inner loop, it ends only that loop, and the outer loop carries on:

    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr[i].length; j++) {
            if (arr[i][j] === 3) {
                break;
            }
            console.log(arr[i][j]);
        }
    }
    1
    2
    5
    6

    When the inner loop reaches the 3, it stops. The 4 is skipped, but the outer loop moves on to the row [5, 6]. If the break sits in the outer loop, outside the inner one, everything stops:

    for (let i = 0; i < arr.length; i++) {
        if (arr[i][0] === 3) {
            break;
        }
        for (let j = 0; j < arr[i].length; j++) {
            console.log(arr[i][j]);
        }
    }
    1
    2

    To leave both loops from inside the inner one, put a label in front of the outer loop and name it in the break:

    outer: for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr[i].length; j++) {
            if (arr[i][j] === 3) {
                break outer;
            }
            console.log(arr[i][j]);
        }
    }
    1
    2

    Inside a function, return is often a cleaner way to leave nested loops, since it ends the whole function at once.

    Common mistakes

    • Reusing the same variable name. If both loops use i, the inner let i hides the outer one inside its own body, which makes the code confusing. Use distinct names such as row and col, or i and j.
    • Putting the newline in the wrong place. It belongs after the inner loop and inside the outer one.
    • Using the wrong length. In a loop over a two-dimensional array, the inner bound is arr[i].length.
    • Expecting break to leave every loop. It ends only the innermost one.
    • Underestimating the cost. Two nested loops over n items run their body about n * n times. A thousand items means a million passes.

    Key takeaways

    • The inner loop restarts and finishes completely on every pass of the outer loop.
    • The inner body runs (outer passes) × (inner passes) times.
    • Rows go in the outer loop and columns in the inner one; the newline goes between the two.
    • break leaves only the innermost loop unless you use a label or a return.
    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free