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
How to Install 2 Anacondas (Python 2 and 3) on MAC Os
How to Sort Objects by Multiple Keys
Execute a File with Arguments in Python Shell
Numpy Random Choice to Produce a 2D-Array with All Unique Values
Converting Python Dict to Kwargs
How to Dynamically Create Derived Classes from a Base Class
Dangers of Sys.Setdefaultencoding('Utf-8')
Save Classifier to Disk in Scikit-Learn
Share Large, Read-Only Numpy Array Between Multiprocessing Processes
Doing Something Before Program Exit
Pandas: Conditional Rolling Count
Append to a List Defined in a Tuple - Is It a Bug