timothy sorenson
timothy sorenson

Reputation: 11

Partial nest for loops

NOTE: corrected question!

It is well-known that itertools allows for easy creation of nested for loops using itertools.product. But the following is what I want and can't do yet. Using

lfl = int(input( "length of first loop: "))
nol = int(input( "number of loops: "))

Causing:

I want an equivalent to:

for i1 in range(1,12):
    for i2 in range(i1,12):
        for i3 in range(i2,12):
            for i4 in range(i3,12):
                function(i1,i2,i3,i4)

itertools.product does way to many.

Or the more general question where nol causes the creating of func_1(x), func_2(x,y), .... func_nol-1(x,y,...) and the code needs to be equivalent to:

for i1 in range(1,12):
    for i2 in range(func_1(i1),12):
        for i3 in range(func_2(i1,i2),12):
            for i4 in range(func_3(i1,i2,i3),12):
                function(i1,i2,i3,i4)

And one more further generalization would be

for i1 in range(1,12):
    for i2 in range(start_func_1(i1, *global),end_func_(12, *global)):
        for i3 in range(start_func_2(i1,i2,*global),end_func_2(12,*global):
            for i4 in range(start_func_3  etc....

Upvotes: 1

Views: 111

Answers (3)

lynn
lynn

Reputation: 10784

For your corrected question, try combinations_with_replacement instead of product on your list of ranges:

from itertools import combinations_with_replacement

nums = [10, 11, 12, 13]
for c in combinations_with_replacement(nums, 3):
    print c

prints

(10, 10, 10)
(10, 10, 11)
(10, 10, 12)
(10, 10, 13)
(10, 11, 11)
(10, 11, 12)
(10, 11, 13)
(10, 12, 12) 
...

Upvotes: 1

Lukas Graf
Lukas Graf

Reputation: 32580

This is exactly equivalent to the code you provided:

from itertools import product

lfl = 12
nol = 4

ranges = (range(i, lfl) for i in range(1, nol + 1))
args = product(*ranges)

for arg in args:
    function(*arg)

It uses a generator expression to build the list of ranges used for the loops to pass to itertools.product and argument list unpacking to pass a single tuple of arguments as separate arguments to the function / to product().

Demonstration:

from itertools import product

def function(*args):
    return args

results_nested = []
results_product = []

for i1 in range(1, 12):
    for i2 in range(2, 12):
        for i3 in range(3, 12):
            for i4 in range(4, 12):
                results_nested.append(function(i1, i2, i3, i4))

lfl = 12
nol = 4

ranges = (range(i, lfl) for i in range(1, nol + 1))
args = product(*ranges)

for arg in args:
    results_product.append(function(*arg))


assert results_nested == results_product

Upvotes: 0

DNA
DNA

Reputation: 42597

You can do this using product - you just need to create the 'dimensions' of the loops in an initial preparation step:

from itertools import product

length = 12
loops = 4

ranges = [range(x+1,length) for x in range(loops)]

def f(x):  # accepts a tuple, since the number of arguments may vary
    print("f(%s)" % repr(x))

for t in product(*ranges):
    f(t)

Upvotes: 0

Related Questions