0

i understand that to create dynamic for loops, recursive or itertools module in python is the way to go. Lets say I am doing it in recursive.

What I want is

for var1 in range(var1_lowerlimit, var1_upperlimit, var1_stepsize):
    for var2 in range(var2_lowerlimit, var2_upperlimit, var2_stepsize):
    :
    :
        # do_whatever()

repeat for n loops where n is the number of variables

What I have now is I have 2 lists

variable_list = [ var1, var2, var3, ... ]
boundaries_list = [ [var1_lowerlimit, var1_upperlimit, var1_stepsize], 
                    [var2_lowerlimit, var2_upperlimit, var2_stepsize], ...]

def dynamic_for_loop(variable_list , boundaries_list, no_of_loops, list_index = 0):
    if no_of_loops <= 0:
        # do_whatever()
    else:
        lower_bound = boundaries_list[list_index][0]
        upper_bound = boundaries_list[list_index][1]
        step_size = boundaries_list[list_index][2]
        for index in range(lower_bound, upper_bound, step_size):
            list_index += 1
            try:
                dynamic_for_loop(variable_list , boundaries_list, no_of_loops - 1, list_index)
            except:
                list_index = 0
                dynamic_for_loop(variable_list , boundaries_list, no_of_loops - 1, list_index)

I did a reset on list_index as it gets out of range, but i couldn't get the result I want. Can someone enlighten me what went wrong?

5
  • 1
    This is obviously over-engineering. What exactly are you trying to achieve? Commented Jun 28, 2016 at 6:36
  • 1
    And don't try to unpack that into separate variables. If your loop count is variable, just process the tuple product() yields dynamically too. Commented Jun 28, 2016 at 6:38
  • its a combination study by vary some variable and each variable has its own boundary to observe, thats why i made the variable and boundary into a list to access it using list_index Commented Jun 28, 2016 at 6:39
  • And how do you call your dynamic_for_loop() in the first place? list_index will go out of bounds if no_of_loops is too large. Commented Jun 28, 2016 at 6:57
  • i call it with just dynamic_for_loop(variable_list , boundaries_list, no_of_loops) Commented Jun 28, 2016 at 7:48

2 Answers 2

5

Use the itertools.product() function to generate the values over a variable number of ranges:

for values in product(*(range(*b) for b in boundaries_list)):
    # do things with the values tuple, do_whatever(*values) perhaps

Don't try to set a variable number of variables; just iterate over the values tuple or use indexing as needed.

Using * in a call tells Python to take all elements of an iterable and apply them as separate arguments. So each b in your boundaries_list is applied to range() as separate arguments, as if you called range(b[0], b[1], b[2]).

The same applies to the product() call; each range() object the generator expression produces is passed to product() as a separate argument. This way you can pass a dynamic number of range() objects to that call.

Sign up to request clarification or add additional context in comments.

2 Comments

I believe you need to unpack the generator you passed to product, i.e. splat it!
thanks! I am quite new to python so I am still digesting that one-liner you just wrote
1

Just for fun, I thought that I would implement this using recursion to perhaps demonstrate the pythonic style. Of course, the most pythonic way would be to use the itertools package as demonstrated by Martijn Pieters.

def dynamic_for_loop(boundaries, *vargs):
    if not boundaries:
        print(*vargs) # or whatever you want to do with the values
    else:
        bounds = boundaries[0]
        for i in range(*bounds):
            dynamic_for_loop(boundaries[1:], *(vargs + (i,)))

Now we can use it like so:

In [2]: boundaries = [[0,5,1], [0,3,1], [0,3,1]]

In [3]: dynamic_for_loop(boundaries)
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2
1 2 0
1 2 1
1 2 2
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 1 2
2 2 0
2 2 1
2 2 2
3 0 0
3 0 1
3 0 2
3 1 0
3 1 1
3 1 2
3 2 0
3 2 1
3 2 2
4 0 0
4 0 1
4 0 2
4 1 0
4 1 1
4 1 2
4 2 0
4 2 1
4 2 2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.