How to Make a For-Loop Pyramid More Concise in Python

How can I make a for-loop pyramid more concise in Python?

By using nested for-loops you're basically trying to create what's known as the (Cartesian) product of the input iterables, which is what the product function, from itertools module, is for.

>>> list(product(range(3),repeat=4))
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 1, 0), (0, 0, 1, 1),
(0, 0, 1, 2), (0, 0, 2, 0), (0, 0, 2, 1), (0, 0, 2, 2), (0, 1, 0, 0),
...

And in your code you can do :

for i,j,k,l in product(range(3),repeat=4):
#do stuff

Based on python documentation, "This function is roughly equivalent to the following code, except that the actual implementation does not build up intermediate results in memory:"

def product(*args, repeat=1):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = [tuple(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)

Python nested looping Idiom

You can use itertools.product:

>>> for x,y,z in itertools.product(range(2), range(2), range(3)):
... print x,y,z
...
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2

Reduce indentation when using Python nested loops

for source_i in sources:
for source_j in sources:
pass

This is the same thing as iterating through the pairs in the Cartesian product of sources and itself. This can be written in one line by importing itertools:

import itertools
for (i,j) in itertools.product(sources, repeat=2):
pass

Same pattern here:

for ni in i.nodes:
for nj in j.nodes:
pass

This can be rewritten as:

for (ni, nj) in itertools.product(i.nodes, j.nodes):
pass

So now you can nest them:

import itertools
for (i,j) in itertools.product(sources, repeat=2):
for (ni, nj) in itertools.product(i.nodes, j.nodes):
if ni != nj:
do_thing(ni, nj)

Number of nested loops by variable

The itertools.product() function should help:

>>> [values for values in product(range(3), repeat=3) if sum(values) == 5]
[(1, 2, 2), (2, 1, 2), (2, 2, 1)]

Seeing that the answer contains anagrams of the same answer, you can reduce the work further by using itertools.combinations_with_replacement():

>>> # 4 digits in [0, 1, 2, 3, 4] summing to 6
>>> for values in combinations_with_replacement(range(5), 4):
if sum(values) == 6:
print(values)

(0, 0, 2, 4)
(0, 0, 3, 3)
(0, 1, 1, 4)
(0, 1, 2, 3)
(0, 2, 2, 2)
(1, 1, 1, 3)
(1, 1, 2, 2)

How do I get around statically nested blocks in python when using multiple nested for loops?

Use itertools.product:

>>> from itertools import product
>>> for comb in product('01', repeat=24):
... print(''.join(comb))
...
000000000000000000000000
000000000000000000000001
000000000000000000000010
000000000000000000000011
000000000000000000000100
...

or even better, binary conversion:

>>> for i in range(2**24):
... print(bin(i)[2:].zfill(24))
...
000000000000000000000000
000000000000000000000001
000000000000000000000010
000000000000000000000011
000000000000000000000100
...


Related Topics



Leave a reply



Submit