6

I know it is terribly inefficient and ugly code, but if I have three for loops, nested inside each other such as so:

for x in range(0, 10):
    for y in range(x+1, 11):
       for z in range(y+1, 11):
           if ...

I want to break the two inner loops and continue to the next iteration of the outer loop if the if statement is true. Can this be done?

KOB
  • 4,084
  • 9
  • 44
  • 88
  • AFAIK the Python founder refused to add a construct to do that because the code would become ugly – William Jan 11 '16 at 15:42
  • 1
    you could write it using variables to store state and test everytime you break / finish the loop – beoliver Jan 11 '16 at 15:44
  • @wil93 Are you referring to the constructs `break` and `continue`? They are recognised in Python, well in Python 3.4 anyway. – KOB Jan 11 '16 at 15:47
  • @beoliver Yes, that does seem like the neatest solution possible, as tglaria has demostrated in his answer below. – KOB Jan 11 '16 at 15:48
  • I was referring to the [*labeled* `break`/`continue` construct](https://www.python.org/dev/peps/pep-3136/), but as I said it was rejected. – William Jan 11 '16 at 15:58

5 Answers5

4

Check some variable after each loops ends:

for x in range(0, 10):
    for y in range(x+1, 11):
        for z in range(y+1, 11):
            if condition:
                variable = True
                break
            #...
        if variable:
            break;
        #...
tglaria
  • 5,678
  • 2
  • 13
  • 17
2

Another option is to use exceptions instead of state variables:

class BreakException(Exception):
    pass

for x in range(0, 10):
    try:
        for y in range(x+1, 11):
           for z in range(y+1, 11):
               if True:
                   raise BreakException
    except BreakException:
        pass

I imagine this could be especially useful if bailing out of more than two inner loops.

MB-F
  • 22,770
  • 4
  • 61
  • 116
  • Very helpful. This should be marked as the answer! – Solomon Vimal Feb 03 '22 at 16:20
  • This is an anti-pattern, exceptions should not be used for the logic side of the code – stribor14 Mar 25 '22 at 13:20
  • 1
    @stribor14 tell that to the Python Devs who thought [`StopIteration`](https://docs.python.org/3/library/exceptions.html#StopIteration) was a good idea. Anyway, you are right. There are cleaner solutions, and I'm just realizing one of them has not been posted yet... – MB-F Mar 25 '22 at 22:13
0
n = False
for x in range(0,10):
    if n == True:
        print(x,y,z)
    for y in range(x+1, 11):
        if n == True:
            break
        for z in range(y+1, 11):
            if z == 5:
                n = True
                break

(1, 2, 5)
(2, 2, 5)
(3, 3, 5)
(4, 4, 5)
(5, 5, 5)
(6, 6, 5)
(7, 7, 5)
(8, 8, 5)
(9, 9, 5)
beoliver
  • 5,579
  • 5
  • 36
  • 72
0

A possible solution is to merge the two inner loops to a single one (that can be terminated with break):

import itertools

for x in range(10):
    for y, z in itertools.combinations(range(x+1, 11), 2):
        if condition:
            break
William
  • 2,695
  • 1
  • 21
  • 33
0

Define a function for the inner loops and simply return when the condition is True.

def process_inner(x):
    for y in range(x+1, 11):
       for z in range(y+1, 11):
           if condition:
               return
           # ...


for x in range(0, 10):
    process_inner(x)

I now believe this is a cleaner solution than abusing exceptions or introducing control flow variables.

It's not obvious in the abstract example, but the fact that some loops should be aborted and others not is a sign that these loops have very different purposes. When this is the case, factoring them into separate functions will communicate that difference much clearer than a bunch of nested loops.

MB-F
  • 22,770
  • 4
  • 61
  • 116