The world’s leading publication for data science, AI, and ML professionals.

4 Examples To Help You Understand Nested Loops

Get a better intuition and understanding of how nested for-loops work and how they can be used for various tasks.

Photo by Brent De Ranter on Unsplash
Photo by Brent De Ranter on Unsplash

A nested for loop iterates over multiple indices, for example, rows and columns. A Nested Loop with two levels has an inner loop that is executed for each iteration of the outer loop. In theory, you can nest a loop in as many levels as you want but it is difficult to follow what happens in a loop with more than two levels.

For most tasks, it is possible to use vectorized operations or use built-in functions that are more efficient. But if you are struggling to get your head around the inner workings of nested loops, I hope these examples will help you get a better intuition and understanding of how the nested for-loop works and how they can be used for various tasks.

You can find the code used in this article in this Github repo.

We will solve the following four tasks by using the nested for-loop:

  1. Create a multiplication table
  2. Matrix addition
  3. Create a Hilbert matrix
  4. Find the Bernoulli numbers

Before moving on to the examples, let us use a nested for-loop to iterate over this small matrix. It will print each element’s position (index) and its value so that we can see in what order the nested for-loop iterates over the matrix.

Image by Author
Image by Author

As you can see, the outer loop iterates over the rows, and for each row the inner loop iterates over all elements in that row. In this case, when we loop over a matrix, we follow the convention of naming the indices i and j, which is how you index matrices in math. But you can name them anything that you want and that helps you remember the order of the iterations.


Multiplication table

Let us begin with a simple example that is very straightforward in its input, iteration, and output. We will create a multiplication table.

  • We specify the size of our table and create a matrix to hold the values
  • Create a nested for-loop, the outer loop iterates over the rows, and the inner loop iterates over the columns
  • Calculate the value for each item in the matrix by multiplying each row index with the column index and store them in the matrix

    Let us break down what happens in each loop.

Outer loop, loop 1, for i=1: The first outer loop stays on index i=1 (row 1) and the inner loop iterates over the entire length of index j, the columns. That is, we iterate over each j element (j=1 to j=n) in this row (i=1):
    Inner loop: The inner loop will iterate from j=1 to j=n:
    i=1, j=1, multiplies i=1 with j=1 and assigns value to mult_table[row i=1, col j=1]
    i=1, j=2, multiplies i=1 with j=2 and assigns value to mult_table[row i=1, col j=2]
    i=1, j=3, multiplies i=1 with j=3 and assigns value to mult_table[row i=1, col j=3]
    ...
    i=1, j=1n, multiplies i=1 with j=n and assigns value to mult_table[row i=1, col j=n]
Outer loop, loop 2, i=1: The second outer loop stays on index i=2 (row 2) and the inner loop iterates over the entire length of index j, the columns:    
    Inner loop: The inner loop will iterate from j=1 to j=n:
    i=2, j=1, multiplies i=2 with j=1 and assigns alue to mult_table[row i=2, column j=1]
    i=2, j=2, multiplies i=2 with j=2 and assigns value to mult_table[row i=2, column j=2]
    i=2, j=3, multiplies i=2 with j=3 and assigns value to mult_table[row i=2, column j=3]
    ...
    i=2, j=n, multiplies i=2 with j=n and assigns value to mult_table[row i=2, j=n]

The loop continues to iterate like this, every element in the columns for each row until we have iterated over the last row n.

Outer loop, loop n, i=n: The last outer loop stays on index i=n (row n) and the inner loop iterates over the entire length of index j, the columns:
    Inner loop: The inner loop will iterate from j=1 to j=n:
    i=n, j=1, multiplies i=n with j=1 and assigns value to mult_table[row i=n, col j=1]
    i=n, j=2, multiplies i=n with j=2 and assigns value to mult_table[row i=n, col j=2]
    i=n, j=3, multiplies i=n with j=3 and assigns value to mult_table[row i=n, col j=3]
    ...
    i=n, j=n, multiplies i=10 with j=n and assigns value to mult_table[row i=n, col j=n]

In this nested for-loop, we filled the multiplication table one row at a time, adding values to the columns from left to right. Each iteration of row i contains, or nests, 10 iterations of the columns j.


Matrix addition

In matrix addition, the matrices being added must have the same dimensions (number of rows and columns). Matrix addition is a simple operation where we add the corresponding elements of the two matrices.

The element in the first row (i=1) and first column (j=1) of A (a_11) is added to the corresponding element in the first row (i=1) and first column (j=1) of B (b_11) and so on.

Image by Author
Image by Author

We will use small numbers that make it easy to see each addition of the matrices.

Image by Author
Image by Author
  • We create two matrices, A and B, that we will add. We also create a matrix, C, where we store the result.
  • Create a nested for-loop, the outer loop iterates over the rows, and the inner loop iterates over the columns.
  • We add each corresponding element in matrix A and B and store the sum in the corresponding index in matrix C.

    In this example, the iterations follow the same pattern as in the multiplication table. The only difference is that it iterates over three matrices, A, B, and C, at the same time.

Outer loop, loop 1, i=1: The first outer loop stays on index i=1 (row 1) and the inner loop iterates over the entire length of index j (j=1 to j=3), for all three matrices A, B and C:
    Inner loop: The inner loop will iterate from j=1 to j=3:
    Adding matrix A[row i=1, col j=1] to matrix B[row i=1, j=1] and assigns value to matrix C[row i=1, col j=1]
    Adding matrix A[row i=1, col j=2] to matrix B[row i=1, j=2] and assigns value to matrix C[row i=1, col j=2]
    Adding matrix A[row i=1, col j=3] to matrix B[row i=1, j=3] and assigns value to matrix C[row i=1, col j=3]
Outer loop, loop 2, i=2: Here i=2 (row 2 in all matrices), and the inner loop iterates over the entire length of index j (j=1 to j=3), for all three matrices A, B and C.
    Inner loop: The inner loop will iterate from j=1 to j=3:
    Adding matrix A[row i=2, col j=1] to matrix B[row i=2, j=1] and assigns value to matrix C[row i=2, col j=1]
    Adding matrix A[row i=2, col j=2] to matrix B[row i=2, j=2] and assigns value to matrix C[row i=2, col j=2]
    Adding matrix A[row i=2, col j=3] to matrix B[row i=2, j=3] and assigns value to matrix C[row i=2, col j=3]

The Hilbert matrix

The Hilbert matrix is a square matrix where each element is a unit fraction defined as:

Image by Author
Image by Author

This is the 5×5 Hilbert matrix:

Image by Author
Image by Author

We will define a function that creates an arbitrarily large Hilbert matrix:

  • Create a matrix H of a chosen size
  • Create a nested for-loop, the outer loop iterates over the rows, and the inner loop iterates over the columns
  • Calculate the value for each item in the matrix

    In this loop, it follows the pattern as before, filling the matrix one row at a time, with values in the columns from left to right. For each element, it calculates the unit fraction according to the formula and assigns the value to the Hilbert matrix.

Outer loop, loop 1, i=1: The first outer loop stays on index i=1 (row 1) and the inner loop iterates over the entire length of index j, the columns. That is, we iterate over each j element (j=1 to j=n) in this row (i=1):
    Inner loop: The inner loop will iterate from j=1 to j=n:
    i=1, j=1, calculates 1/(row i=1 + col j -1) and assigns value to hilbert[row i=1, col j=1]
    i=1, j=2, calculates 1/(row i=1 + col j -1) and assigns value to hilbert[row i=1, col j=2]
    i=1, j=3, calculates 1/(row i=1 + col j -1) and assigns value to hilbert[row i=1, col j=3]
    ...
    i=1, j=n, calculates 1/(row i=1 + col j -1) and assigns value to hilbert[row i=1, col j=n]
Outer loop, loop n, i=n: The last outer loop stays on index i=n (row n) and the inner loop iterates over the entire length of index j, the columns. That is, we iterate over each j element (j=1 to j=n) in this row (i=n):
    Inner loop: The inner loop will iterate from j=1 to j=n:
    i=n, j=1, calculates 1/(row i=n + col j -1) and assigns value to hilbert[row i=n, col j=1]
    i=n, j=2, calculates 1/(row i=n + col j -1) and assigns value to hilbert[row i=n, col j=2]
    i=n, j=3, calculates 1/(row i=n + col j -1) and assigns value to hilbert[row i=n, col j=3]
    ...
    i=n, j=n, calculates 1/(row i=n + col j -1) and assigns value to hilbert[row i=n, col j=n]

Finding the Bernoulli numbers

Finally, I will show an example of how we can solve mathematical equations that have indices by using nested for-loops. We will write a function to find the first numbers of the second Bernoulli numbers. The second Bernoulli number can be represented with the following equation:

Image by Author
Image by Author

To get an idea of how you calculate the numbers, let us calculate the second number B_2. When k=0, there is only one term j=0.

Image by Author
Image by Author

When k=1, there are two terms for j=0 and j=1 that need to be calculated.

Image by Author
Image by Author

When k=2 there are three terms for j=0, j=1, j=2.

Image by Author
Image by Author

As you can see, the equation becomes hairy quite quickly if we want to find higher Bernoulli numbers. We can let R do the work for us with a nested for-loop.

In this example, we don’t iterate over rows and columns as we did in the previous three examples. Rather, we are calculating each term for k and j as shown above in the example of solving Bernoulli number 2.

  • The number of iterations for the outer loop, which is the outer summation of k in the equation, ranges from 0 to n as defined in the equation.
  • The number of iterations for the inner loop, which is the inner summation of j, is determined by k, since it ranges from 0 to k.

Conclusion

For some reason, I find that there is something confusing about nested loops, even if the logic of them is very clear. More often than I like to admit, a nested loop gives a result that I did not expect and that was not intended. On those occasions, I find that it helps to go back to simple examples like these to "reset" my thinking. I hope these examples can help you in case you find nested loops confusing.

You can find the code used in this article in this Github repo.


Related Articles