Given a list of upperbounds: B1, B2, .. BN;
Dependency Functions: f1, ..., fN-1,
I'm wondering if there's a recipe using itertools or other classes in python for:
for i1 in range(0, B1):
for i2 in range(f1(i1), B2): ...
for iN in range(fN-1(iN-1), BN)
dostuff(i1, i2, ... iN)
Where there are N levels of nesting?
I want to use this helper function like this:
dependentProducts(Bs, fs, dostuff),
which returns a list or iterable
Ideally, the implementation would be iterative instead of recursive.
There is no limitation on the chaining of loops. In the nested loop, the number of iterations will be equal to the number of iterations in the outer loop multiplied by the iterations in the inner loop. In each iteration of the outer loop inner loop execute all its iteration.
product was significantly slower than my nested for loops. The results from profiling (based on 10 runs per method) was an average of ~0.8 seconds for the nested for loop approach and ~1.3 seconds for the itertools. product approach.
In Python programming language there are two types of loops which are for loop and while loop. Using these loops we can create nested loops in Python. Nested loops mean loops inside a loop. For example, while loop inside the for loop, for loop inside the for loop, etc.
Nested For LoopsLoops can be nested in Python, as they can with other programming languages. The program first encounters the outer loop, executing its first iteration. This first iteration triggers the inner, nested loop, which then runs to completion.
An iterative solution using @LaurentLAPORTE's setup. Put this code right under his and it should work. My args
is a stack of the arguments fed into dostuff
whenever it's full. The actual solution is the middle part, top and bottom parts are just testing.
stefan = []
def dostuff(*args):
stefan.append(list(args))
args = [-1]
while args:
n = len(args)
args[-1] += 1
if args[-1] >= B[n-1]:
args.pop()
elif n == len(B):
dostuff(*args)
else:
args.append(F[n](args[-1]) - 1)
assert expected == stefan
Here is an example of what you want:
B = [10, 15, 20, 5]
F = [lambda x: x,
lambda x: x * x,
lambda x: x * 2 - 5]
def dostuff(i0, i1, i2, i3):
print((i0, i1, i2, i3))
expected = []
for i0 in range(0, B[0]):
for i1 in range(F[0](i0), B[1]):
for i2 in range(F[1](i1), B[2]):
for i3 in range(F[2](i2), B[3]):
expected.append([i0, i1, i2, i3])
I found a recursive solution like this:
def iter_rec(found, fL, bL):
if fL and bL:
ik = found[-1] if found else 0
fk = fL[0]
bk = bL[0]
for i in range(fk(ik), bk):
for item in iter_rec(found + [i], fL[1:], bL[1:]):
yield item
else:
yield found
# prepend the null function to ensure F and B have the same size
F = [lambda x: 0] + F
current = [item for item in iter_rec([], F, B)]
We have the same result.
assert expected == current
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With