Nested Loops in Python (original) (raw)

Nested loops in Python allow you to place one loop inside another, enabling you to perform repeated actions over multiple sequences. Understanding nested loops helps you write more efficient code, manage complex data structures, and avoid common pitfalls such as poor readability and performance issues.

By the end of this tutorial, you’ll understand that:

This tutorial provides practical examples and optimization techniques for using nested loops effectively in your Python programs.

Take the Quiz: Test your knowledge with our interactive “Nested Loops in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:


Nested Loops in Python

Interactive Quiz

Nested Loops in Python

Nested loops allow you to perform repeated actions over multiple sequences, but is there more? Test your understanding of nested loops in Python!

Getting Started With Nested Loops in Python

Loops are fundamental building blocks in programming, allowing you to iterate through actions efficiently. In Python, there are two primary types of loops: the for loop and the while loop. Both serve the same purpose —executing a block of code multiple times—but they differ in how they operate and in their use cases:

You create a nested loop by placing one loop inside another. This structure is especially helpful when working with multidimensional data, generating patterns, or handling tasks that involve several layers of repetition.

In a nested loop, the first loop is called the outer loop, and the loop inside is the inner loop. So, for every iteration of the outer loop, the inner loop runs completely before the outer loop moves to the next iteration.

Here’s the basic syntax of a nested loop:

The outer_iterable must be a list, a dictionary, or some other sequence of items that you can iterate over. The same applies to the inner_iterable. The <body> inside the inner loop contains the code that runs once for each for loop step in the inner_iterable. Since the inner loop is nested inside the outer loop, it runs in full for each iteration of the outer loop.

A good analogy for a nested loop is the hour and minute hands of a clock. The hour hand moves slowly around the clock, completing one full revolution every twelve hours. Meanwhile, the minute hand moves at a much faster rate, completing a revolution every hour. While both hands rotate at different speeds, they work together, each completing their own cycle within the same clock.

Here’s how the clock logic looks in Python code:

As you can see, every time the minute hand completes a cycle, the hour hand moves to the next hour. :02d is a format specifier that ensures the number is printed as a two-digit-wide integer value.

Now that you’ve been introduced to nested loops, it’s time to explore some practical examples. You’ll become familiar with writing programs using nested loops in the following section.

Exploring Practical Examples of Nested Loops

As you just learned, nested loops have a number of use cases. Here, you’ll have a look at a few examples. These examples are interesting and practical, allowing you to have fun as you explore their syntax and semantics.

Printing Patterns With Nested Loops

Being able to print any pattern of your choosing is a fascinating feat in programming. One way you can achieve this is by understanding how nested loops work. The code snippet below builds a sail pattern using a few simple symbols. While this may not seem particularly exciting, consider it a first step toward creating something spectacular—like a spaceship:

Here’s what the code does line by line:

This way, the spaceship is essentially built piece by piece. Adding one piece at a time, you could increase its size or expand its structure.

Generating a Multiplication Table

Multiplication tables display the results of numbers multiplied by one another. These tables are commonly used in grade school for quick reviews of multiplication operations. Nested for loops are a great way to generate multiplication tables in Python:

The example above displays the multiplication of numbers. The outer loop iterates through numbers 1 to 10, while the inner loop iterates through numbers 1 to 3.

For every iteration of the outer loop, the current value is multiplied by each number in the inner loop. After finishing one row, print() moves to the next line. This creates a structured multiplication table. You could give this a go yourself by using different ranges and printing the result.

In the next section, you’ll explore how to use nested loops to sum all the elements in a nested list.

Summing Elements in Multidimensional Lists

Another application of nested loops is processing elements in more than one dimension. A multidimensional or nested list is a list that contains other lists as its elements. To sum all elements in a nested list, you can use nested loops.

Staying true to the theme of space travel, you can picture nested list summation this way:

Here, you use a nested for loop to handle resource collection from altruistic planets in a star system. Each sublist in resource_donators represents a planet, and each number in the sublist represents a unit of a resource—say, something known throughout the galaxy as foodonium. The total_resources is initialized to 0.

The outer loop iterates through each planet, and the inner loop goes through each individual resource, adding it to total_resources. Suppose that one planet provides 8, 6, and 3 units of foodonium. After processing all planets, the final total is printed, and the spaceship can continue on its way.

Next, you’ll take a look at how you can use nested loops to create pairwise combinations.

Creating Pairwise Combinations

When building programs, you may have to work with datasets that require you to make comparisons or work with data in pairs. In the example below, you’ll find a program that generates all possible matchups between players in a friendly game of space ball:

With this approach, you can generate all possible matchups—including self-matchups—demonstrating that pairwise combinations are possible with nested loops. You may have noticed that players are allowed to play against themselves, which you might not want. Click the collapsible section below to learn how to get rid of self matchups in space ball.

You’ll have noticed that space ball allows players to be matched against themselves. Perhaps that’s just the nature of the game, or maybe you’d prefer to prevent that from happening. How could you remove self-matchups from the program above? One solution is to add an if condition to filter them out, as shown in the code below:

This code example shows one way to generate pairwise combinations while filtering out self-matchups. This pattern comes in handy whenever you’re comparing elements in a group.

As you’ve seen, nested loops make it easy to create pairwise combinations, whether you’re including or filtering out matches. This isn’t only useful in games, but also in real-world scenarios like comparing data entries. With that under your belt, you’ll now take a look at an example that uses while loops in nested situations.

Working With while Loops in Nested Structures

So far, you’ve seen several examples using for loops in nested loops. There are also a number of situations where you’ll prefer to use while loops instead. For example, say that you’re building an app that prints each letter of a word:

The example above shows a program that allows a user to type a word at the prompt, with each letter of the word eventually printed to the screen. A break keyword is added to halt the execution of the program when exit is typed.

Whether you’re using for loops or while loops in nested loops, you need to be cautious when using them. Poor usage can lead to a number of problems, such as reduced readability and performance issues, as you’ll soon see.

Avoiding Common Nested Loop Pitfalls

When used improperly, nested loops can cause more problems than solutions. It’s therefore crucial to be aware of potential pitfalls you may encounter when using them to build programs, including:

In the next sections, you’ll have a closer look at each of these pitfalls and investigate ways to prevent them.

Handling Variable Scoping Issues

In Python, variables defined within a loop are accessible in the enclosing scope. This means that outer loop variables can be used inside the inner loop. However, unintended side effects may occur when an outer loop variable is modified in the inner loop, or when they both use the same variable.

If you forget to keep track of such cases, you may be forced to deal with bugs later on, which could be a real hassle. Consider the following code:

What you’ll observe here first is that department refers to the department name associated with an employee, as defined by the outer for loop. However, the inner for loop also refers to a department, which is a value in a list of dictionaries. The original definition of department by the outer loop is overwritten by the inner loop, causing logical errors.

One way to solve this is to declare different variable names for inner and outer loops:

Now you can be certain that department and dept are handled separately. In order to avoid problems such as this, you should always avoid reusing the same variable name in both outer and inner loops, and be cautious when modifying an outer loop variable inside an inner loop.

Addressing Poor Readability

A major challenge when working with nested loops is poor readability. As the complexity of a program increases, deeply nested loops can make code difficult to read and maintain. While nested loops are sometimes necessary, excessive nesting can make it harder for other developers—or even for you—to understand what’s going on in your code.

Consider the following example, which is a search protocol for when an intruder ventures into your ship:

At first glance, this code may seem manageable, even though there are several areas to search through. However, you might be taken aback by the number of lines of output in the terminal when you run the program.

Now imagine being on an enterprise-level ship, with even more levels of nesting introduced. A piece of code with four or five nested loops can quickly become unreadable and difficult to maintain, making debugging a waking nightmare.

One reason why nested loops in Python are notorious for poor readability is that Python is an indented language, in contrast to a language like JavaScript that relies on curly brackets to distinguish code blocks. Another challenge is that it can become difficult to keep track of which loop is controlling which part of the logic. These factors combined make readability a crucial consideration when working with nested loops.

Another important consideration when it comes to nested loops is how they affect performance. You’ll explore this next.

Dealing With Performance Bottlenecks

To understand how poorly written nested loops can affect performance, it helps to briefly explore the concept of time complexity. Time complexity is a way to measure how fast an algorithm runs relative to the rate at which the input size grows, denoted by O(n).

The O represents Big O notation, where n is the size of the input. It’s a widely used measure of performance, grouped into complexities, arranged in order from most to least efficient:

Complexity Big O Description
Constant Time O(1) Runtime doesn’t change with input size
Logarithmic Time O(log n) Runtime grows slowly as input size increases
Linear Time O(n) Runtime grows directly with input size
Quadratic Time O(n2) Runtime grows with the square of the input size
Exponential Time O(2n) Runtime doubles with each additional input
Factorial Time O(n!) Runtime grows extremely fast (factorial growth)

A single for loop runs in O(n) time. While this may not seem too bad for performance, imagine having six layers of nested loops. In that case, the time complexity is O(c × r × a × w × l), where each letter represents a loop. That’ll lead to performance bottlenecks. So you can see why nested loops quickly become inefficient, especially for large programs where each loop increases the time complexity.

The example below shows an algorithm for detecting runaway clones aboard your ship—an unfortunate side effect of a well-meaning science experiment:

As you can see, there are only two for loops, so the time complexity may be O(c × r) denoted as O(n2).

For a small example like this, you may get away with it, but for a large enough input, it would negatively affect performance. Paying attention to performance would help you write more efficient algorithms.

This code has a fun narrative of identifying duplicate clones on a ship. However, in reality, it’s identifying duplicate numbers in a list. It goes through each first_id one by one while keeping track of its location using enumerate(). If any of the numbers in the list match, then you identify the number as a duplicate. More interestingly, you capture a clone.

A solution to such a problem may be to forego nested loops in preference for more optimized techniques. In the example above, you could use a Python set or collections.Counter instead of nested loops. In both cases, the time complexity amounts to O(n), which has a better performance than O(n2).

In the code below, you can see how this works with a set:

This next example shows how you can detect duplicates using a Counter:

Here, Counter detects the duplicates for you. Keep in mind that you don’t have to let go of nested loops entirely in some situations. Nested loops can be optimized, and you’ll learn exactly how next.

Optimizing Nested Loops in Python

As you’ve seen, nested loops offer powerful capabilities, but like many useful tools, they also have their downsides. You explored some of those limitations in the previous section. In this section, you’ll learn how to optimize nested loops so you can use them more efficiently in your programs.

Using break and continue

Using nested loops may sometimes result in unnecessary iterations. You can control these iterations better by using the break and continue statements.

If a nested for loop were a BLT sandwich, using break would be like eating the top layers and discarding the rest. Using continue, on the other hand, would be like eating the top layers, skipping the lettuce, then finishing the bottom layers. The continue statement skips unnecessary iterations, reducing workload and improving performance.

In other words, the break statement lets you exit a loop before it finishes, and the continue statement lets you skip iterations that aren’t needed. If you were an astronaut floating in zero gravity who hated lettuce, a program for how you eat a massive BLT sandwich might look like this:

If you were to keep running the program even after finding your target bacon, the program would use up more resources. The break statement fixes this by terminating the loop early.

Nested for loops can be optimized with continue like in this example:

The program skips non-bacon layers in the BLT, reducing unnecessary processing. By handling it this way, the code becomes more efficient and avoids extra workload. Both break and continue statements help improve the efficiency of nested loops, especially in tasks that involve searching or filtering.

Replacing Nested Loops With List Comprehension

With list comprehensions, you can replace the intimidating hill of nested loops with a more compact and readable expression. While list comprehensions don’t necessarily improve performance or reduce time complexity—especially in nested iterations—they often make your intent clearer and your code easier to understand.

The following example illustrates this with a crewmate determined to make towering stacks of pancakes:

This is an example of a traditional nested for loop. You’ll notice that the outer and inner loops use different variable names. This is an important detail that helps you avoid the variable scoping issues you learned about earlier.

Below, you’ll find the same program, but this time using list comprehension for the nested loops:

Note that while list comprehensions may look clean and concise, they aren’t always the better choice. Readability can suffer when the logic becomes too complex, especially with nested structures. This goes against the Zen of Python, which emphasizes that readability is important.

So, the question boils down to whether list comprehension is actually more efficient than nested loops. A good answer to that is this—it depends. For straightforward transformations or filtering, list comprehensions are often ideal. But when your logic involves deep nesting, a traditional loop may be better. Ultimately, the key is to strike a balance between readability and efficiency.

The optimization techniques you’ve explored may appear to be minor modifications that make nested loops better, but in larger applications, they can significantly impact performance. That’s why it’s important to recognize when nested loops are unnecessary—and, when you do use them, to manage them thoughtfully and efficiently.

Conclusion

Nested loops are a powerful tool in Python. With them, you can handle complex iterations and work through difficult algorithms. They’re well-suited for tasks like handling multidimensional data, searching, and returning structured outputs such as custom patterns. However, when used poorly, they can lead to problems with performance, maintainability, and readability.

In this tutorial, you’ve learned how to:

Understanding nested loops helps you write more efficient code, manage complex data structures, and avoid common pitfalls such as poor readability and performance issues.

Frequently Asked Questions

Now that you have some experience with nested loops in Python, you can use the questions and answers below to check your understanding and recap what you’ve learned.

These FAQs are related to the most important concepts you’ve covered in this tutorial. Click the Show/Hide toggle beside each question to reveal the answer.

You use nested loops in Python to run a loop inside another loop, allowing you to iterate over multiple sequences or perform repeated actions within each iteration of the outer loop.

You’ll find nested loops useful for handling multidimensional data, generating patterns, or performing repetitive tasks that require multiple layers of iteration.

You can break out of nested loops using the break statement to exit the current loop.

Nested loops can lead to poor readability, variable scoping issues, and performance bottlenecks, especially when they’re deeply nested or when you’re handling large datasets.

Take the Quiz: Test your knowledge with our interactive “Nested Loops in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:


Nested Loops in Python

Interactive Quiz

Nested Loops in Python

Nested loops allow you to perform repeated actions over multiple sequences, but is there more? Test your understanding of nested loops in Python!