4

How do I make a number of nested loops where depth is a parameter. I am thinking of a function which takes depth as a parameter

def make_nested_loops(depth):
    ...

And, the result for depth=3 is the following

for i1 in range(10):
    for i2 in range(i1 + 1, 10):
        for i3 in range(i2 + 1, 10):
            # do stuff

So far I've been able to do this using strings building and exec command. But I think there is better and more efficient way to do it.

Bilal
  • 18,478
  • 8
  • 57
  • 72
JJ77
  • 43
  • 1
  • 5
  • Nested loops create a larger complexity. What is it you're looping through and what are you trying to accomplish? – J0hn Jul 07 '17 at 13:37
  • Why? The inner loops *depend* on the containing loops, so you can't really flatten it. – chepner Jul 07 '17 at 13:38
  • 1
    By the way, what is `make_nested_loops` supposed to return? A loop isn't an object, it's a syntactic construct. Perhaps it should take a second argument that is a function to call that receives a tuple `(i1, i2, ...)` as an argument and is called where `#do stuff` occurs. – chepner Jul 07 '17 at 13:46
  • @chepner It is supposed to return a list or a dictionary of tuples, where each tuple's length is exactly the depth. – JJ77 Jul 07 '17 at 13:53

2 Answers2

1

The max number of nested loops you can have is 21 I think. So what you could do is have 21 nested loops in your function, and check if desired depth has been achieved at each loop. If not, add one to current depth variable.

Cary Shindell
  • 1,336
  • 8
  • 25
  • "The max number of nested loops you can have is 21" Source please? – Right leg Jul 07 '17 at 13:46
  • @Rightleg I think she may be right. I checked [here](http://bugs.python.org/issue986720) and one of the author's said 20 is the max. I'm still not 100% sure though and I'm still looking. – Christian Dean Jul 07 '17 at 13:47
  • 2
    @ChristianDean Well I just tested and that's right, 19 works but 20 does not. For the record, it fails with `SyntaxError: too many statically nested blocks`. But I do want a source. – Right leg Jul 07 '17 at 13:48
  • 2
    Actually I cannot upvote this answer as it is not a good answer to the question, but I want to thank for letting me know that Python had such a limitation. – Right leg Jul 07 '17 at 13:52
  • 1
    My source is experience, I once tried to make a ton of nested loops and it crashed with more than 19. – Cary Shindell Jul 07 '17 at 13:55
  • @Rightleg of course recursion would be a better solution, but the question asked for how to do it with nested loops so that is what I gave – Cary Shindell Jul 07 '17 at 13:57
  • I took the liberty to ask a [question about this](https://stackoverflow.com/questions/44972719/increase-the-number-of-statically-nested-block). If you happen to have more details, please share them with us. – Right leg Jul 07 '17 at 14:04
1

An inefficient but simple approach would be to use itertools.product and filter unwanted tuples:

def make_tuples(depth, n):
    for i in itertools.product(range(n), repeat=depth):
        if sorted(i) < i:
            continue
        yield i

More efficient would be a recursive generator:

def make_tuples(depth, n, start=0):
    if depth == 0:
        yield ()
    else:
        for x in range(start, n):
            for t in make_tuples(depth - 1, n, x + 1):
                yield (x,) + t

Using it would look like

for (i1, i2, i3) in make_tuples(3, 10):
    # do stuff with i1, i2, i3

If the depth is really dynamic, you can't of course unpack the tuples coming from make_tuples. The body will have to know what to do with tuples of fixed but unknown length.

for tpl in make_tuples(n, 10):
    # Do stuff with tpl
chepner
  • 497,756
  • 71
  • 530
  • 681