0

Is it possible to add/reduce number of nested for loops in a function based on the length of input?

For example: Based on a certain input of length 3, I may need to use 1 nested for loop (for loop inside another for loop). Similar to this,

for i in range(0, len(input)+1):
    for j in range(i+1, len(input)+1):

However, when the input length is 4, I could have achieved my result if I could introduce additional for loop inside the already existing nested for loop, which means,

for i in range(0, len(input)+1):
    for j in range(i+1, len(input)+1):
        for k in range(j+1, len(input)+1):`

Similarly, if the input length is 5, then I would like to introduce another for loop,

for i in range(0, len(input)+1):
    for j in range(i+1, len(input)+1):
        for k in range(j+1, len(input)+1):
            for l in range(k+1, len(input)+1):`

The pattern is, there will be n-1 number of for loops for an input of length n.

Is it possible create such a function in Python?

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
Maruf Sazed
  • 61
  • 1
  • 2
  • 5
  • 2
    Sounds like an XY Problem. What is the real problem you are trying to solve ? – rafaelc Sep 22 '18 at 12:54
  • 1
    We could use an example. Recurrency fits here if applied properly. – Tom Wojcik Sep 22 '18 at 12:56
  • For example, I have a list of numbers/alphabets as input. Input = [1,2,3,4] I want to create a combination of all the individual elements. Similar to following, [1],[2],[3],[4],[1,2],[1,3],[1,4],[2,3],[2,4],[3,4],[1,2,3],[1,2,4],[1,3,4],[2,3,4],[1,2,3,4] Perhaps, there are different ways to solve the actual problem. But while trying to solve this I came up with the question of variable number of nested for loops. – Maruf Sazed Sep 22 '18 at 13:08
  • @MarufSazed that being said, the question is a duplicate ;) Check the answers in the link – rafaelc Sep 22 '18 at 13:15
  • 1
    This is not a good dupe @RafaelC; this question is about a variable number of for loops whereas the alleged dupe you linked is about generation combinations. – Reblochon Masque Sep 22 '18 at 13:17
  • 1
    @ReblochonMasque alright, will let the question open. But will just state the link to the correct solution for this: https://stackoverflow.com/questions/464864/how-to-get-all-possible-combinations-of-a-list-s-elements . Building variable number of for loops is a *terrible design*. – rafaelc Sep 22 '18 at 13:19
  • Again, not a good dupe @MarkDickinson – Reblochon Masque Sep 22 '18 at 13:27

1 Answers1

2

From this article the code written in C and hastily translated to python gives you this:

If we look at how the nested loops work, we see that the inner most loop works most of time and the upper loops are needed only when we run out of values in the inner loops.

To convert this into a dynamic nested loop we can represent the different loop variables in an array. For simplicity lets assume that the upper bound of these variables are a constant as in the above example.

To implement a dynamic nested loop we need to increment the inner most loop variable until we run out values. Only then do we need to look at changing the upper level loop variables.

While this snippet is generating combinatorics, it is maybe possible to imagine re-using it for a different purpose.

As mentioned in the comments, it may not be a good design choice.
There has to be a better (more pythonic) way using generators, or maybe async, than increasing the level of indirection.

Of course, there is also recursion, but that was not the point of the question.

Generating dynamically nested loops

MAXROWS = 4      #    contains the number of levels
MAXVALUES = 2    #    contains the maximum combination for a given nested variables.

display = ['1', '2', '3', '4', '5', '6', '7', '8', '9']

arrs = [0] * MAXROWS   # represent the different variables in the for loops                      
status = False

while not status: 

    total = 0
    # calculate total for exit condition
    for r in range(MAXROWS):
        total += arrs[r]
        # test for exit condition
    if total == (MAXVALUES - 1) * MAXROWS:
        status = True

    # printing
    for r in range(MAXROWS):
        print(display[arrs[r]], end=' ')  # print(arrs[r])
    print()

    # increment loop variables
    change = True
    r = MAXROWS-1    # start from innermost loop

    while change and r >= 0:
    # increment the innermost variable and check if spill overs
        if (arrs[r] + 1) > MAXVALUES-1:    
            arrs[r] += 1
            arrs[r] = 0     #  // reintialize loop variable
            # Change the upper variable by one
            # We need to increment the immediate upper level loop by one
            change = True   
        else:
            arrs[r] += 1
            change = False   # Stop as there the upper levels of the loop are unaffected

            # We can perform any inner loop calculation here arrs[r]

        r -= 1  #  move to upper level of the loop

output:

1 1 1 1 
1 1 1 2 
1 1 2 1 
1 1 2 2 
1 2 1 1 
1 2 1 2 
1 2 2 1 
1 2 2 2 
2 1 1 1 
2 1 1 2 
2 1 2 1 
2 1 2 2 
2 2 1 1 
2 2 1 2 
2 2 2 1 
2 2 2 2
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80