1

I'am solving Euler's project and right now triyn to solve 9 task.

The solution I've found is in 3 nested loops:

for ai in range(1, 100):
   for bi in range(1, 100):
      for ci in range(1,100):
          if ai + bi + ci == 25 and ai * ai = ci:
             break

but when last if find the solution for-loops continues and I wanna break all of them. Is it posible? I thougt about using some flags but it's additional check for each step and makes execution longer.

  • What is `Euler`s project` please explain it in the question as well! – Devesh Kumar Singh May 12 '19 at 13:34
  • 2
    Put the loops in a function and return the answer instead of breaking. – Mark Tolonen May 12 '19 at 13:35
  • if you need `ai + bi + ci == 25` then for `ai = 1` you have to check `bi` only in range `1..24` or even in `1..23` because `ci` has to be at least `1`. – furas May 12 '19 at 13:38
  • if you have `ai + bi + ci == 25` then `ci == 25 - ai - b1` and you can use it with second part `ai * ai == 25 - ai - b1` so you will have one variable less and one loop less. – furas May 12 '19 at 13:42
  • @DeveshKumarSingh, Euler project is a list of math tasks with growning up level of difficulty. You can find it here: https://projecteuler.net/archives – Евгений Крючков May 12 '19 at 14:45
  • just for the record. break only breaks the current loop. and you already get an answer by using exceptions and raising one. another solution is to use a function then return the result, another one is to use an indicator , if the if is reached then a variable of type bool may take true (exitLoop = true) and test it for each loop and use break for each one ( too much code to write but nothins special) – shadow May 12 '19 at 14:45

2 Answers2

6

Because your range() sequences are fixed, you don't need to use nested for loops. Instead, use a single loop over itertools.product():

from itertools import product

for ai, bi, ci in product(range(1, 100), repeat=3):
    if ai + bi + ci == 25 and ai * ai == ci:
         break

Next, remove one of the repeats and lower the range values; you can trivially calculate ci from ai and bi, and ranging beyond 23 is pointless (as ci will only be 1 or greater if ai + bi is 24 or less):

for ai, bi in product(range(1, 23), repeat=2):
    ci = 25 - ai - bi
    if ai * ai == ci:
         break

That ci can be negative here doesn't matter, as ai * ai will always be a positive number.

Note that the above equation has four solutions, so breaking out on the first may not be the correct answer. You can calculate all possible solutions for a given target value with:

def triplets(target):
    return (
        (ai, bi, target - ai - bi)
        for ai, bi in product(range(1, target - 2), repeat=2)
        if ai * ai == target - ai - bi
    )

This returns a generator, so can be asked for a single solution at a time with next():

gen = triplets(25)
print(next(gen, None))

If your inner loop sequences are dependent on the value of a parent loop, and you can't simplify the loop (like the ci = 25 - ai - bi assignment above), then you perhaps need to use nested loops. You can always break out of such structures with an exception you catch; even standard ValueError would do, or create a custom exception:

class Break(Exception):
    pass

try:
    for ai in <some_sequence>:
        for bi in range(<based on ai>):
            if <condition>:
                raise Break
except Break:
    # nested set of loops has exited

or nest the loop in a function and use return:

def nested_loops(<arguments>):
    for ai in <some_sequence>:
        for bi in range(<based on ai>):
            if <condition>:
                return ai, bi
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • What if I need this loops should be different length? For example, ai from 1 to bi and c from 1 to 1000. – Евгений Крючков May 12 '19 at 13:37
  • @ЕвгенийКрючков: if inner loops depend on outer values, then you have to use nesting. You can raise exceptions or nest the loop in a function with `return`. – Martijn Pieters May 12 '19 at 13:40
  • And remember kids... if N is wasn't small enough the good old itertools.product could give you a nice MemoryError [https://stackoverflow.com/questions/8695422/why-do-i-get-a-memoryerror-with-itertools-product](https://stackoverflow.com/questions/8695422/why-do-i-get-a-memoryerror-with-itertools-product) ;) – BPL May 12 '19 at 13:56
  • @BPL: yup, `itertools.product()` materialises all sequences passed to it into tuples. – Martijn Pieters May 12 '19 at 13:59
0

You could either

  • Put it in a function and return the value as soon as it is reached

or

  • Raise an exception once the value is reached, and pass:
try:
    for ai in range(1, 100):
       for bi in range(1, 100):
          for ci in range(1, 100):
              if ai + bi + ci == 25 and ai * ai = ci:
                 raise BreakE
except BreakE:
    pass
Xosrov
  • 719
  • 4
  • 22