user3014653
user3014653

Reputation: 775

python nested list comprehension for arbitrary number of variables

If I have a tuple of dimensions like dims=(2, 3, 4) and I want to generate a list of all possible indices for this array, a good solution I've found is:

dims = (2, 3, 4)
indices = [range(0, d) for d in dims]
strings = ["[%i][%i][%i]" % (i,j,k) for i in indices[0] for j in indices[1] for k in indices[2]]
print strings:
['[0][0][0]', '[0][0][1]', '[0][0][2]', '[0][0][3]', '[0][1][0]', '[0][1][1]', '[0][1][2]', '[0][1][3]', '[0][2][0]', '[0][2][1]', '[0][2][2]', '[0][2][3]', '[1][0][0]', '[1][0][1]', '[1][0][2]', '[1][0][3]', '[1][1][0]', '[1][1][1]', '[1][1][2]', '[1][1][3]', '[1][2][0]', '[1][2][1]', '[1][2][2]', '[1][2][3]']

This is all well and good, but I'm looking for a nice compact way to generate the strings variable where dims is of arbitrary length. I'm trying to avoid a bunch of "if-else" clauses depending on the length of dims. Any ideas?

Upvotes: 3

Views: 163

Answers (2)

Uriel
Uriel

Reputation: 16224

Use itertools.product:

>>> from itertools import product
>>> dims = (2, 3, 4, 5)
>>> list(product(*map(range, dims)))
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3), (0, 0, 0, 4), (0, 0, 1, 0), (0, 0, 1, 1), (0, 0, 1, 2), (0, 0, 1, 3), (0, 0, 1, 4), (0, 0, 2, 0), (0, 0, 2, 1), (0, 0, 2, 2), (0, 0, 2, 3), (0, 0, 2, 4), (0, 0, 3, 0), (0, 0, 3, 1), (0, 0, 3, 2), (0, 0, 3, 3), (0, 0, 3, 4), (0, 1, 0, 0), (0, 1, 0, 1), (0, 1, 0, 2), (0, 1, 0, 3), (0, 1, 0, 4), (0, 1, 1, 0), (0, 1, 1, 1), (0, 1, 1, 2), (0, 1, 1, 3), (0, 1, 1, 4), (0, 1, 2, 0), (0, 1, 2, 1), (0, 1, 2, 2), (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 0), (0, 1, 3, 1), (0, 1, 3, 2), (0, 1, 3, 3), (0, 1, 3, 4), (0, 2, 0, 0), (0, 2, 0, 1), (0, 2, 0, 2), (0, 2, 0, 3), (0, 2, 0, 4), (0, 2, 1, 0), (0, 2, 1, 1), (0, 2, 1, 2), (0, 2, 1, 3), (0, 2, 1, 4), (0, 2, 2, 0), (0, 2, 2, 1), (0, 2, 2, 2), (0, 2, 2, 3), (0, 2, 2, 4), (0, 2, 3, 0), (0, 2, 3, 1), (0, 2, 3, 2), (0, 2, 3, 3), (0, 2, 3, 4), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 0, 2), (1, 0, 0, 3), (1, 0, 0, 4), (1, 0, 1, 0), (1, 0, 1, 1), (1, 0, 1, 2), (1, 0, 1, 3), (1, 0, 1, 4), (1, 0, 2, 0), (1, 0, 2, 1), (1, 0, 2, 2), (1, 0, 2, 3), (1, 0, 2, 4), (1, 0, 3, 0), (1, 0, 3, 1), (1, 0, 3, 2), (1, 0, 3, 3), (1, 0, 3, 4), (1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 0, 2), (1, 1, 0, 3), (1, 1, 0, 4), (1, 1, 1, 0), (1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 1, 3), (1, 1, 1, 4), (1, 1, 2, 0), (1, 1, 2, 1), (1, 1, 2, 2), (1, 1, 2, 3), (1, 1, 2, 4), (1, 1, 3, 0), (1, 1, 3, 1), (1, 1, 3, 2), (1, 1, 3, 3), (1, 1, 3, 4), (1, 2, 0, 0), (1, 2, 0, 1), (1, 2, 0, 2), (1, 2, 0, 3), (1, 2, 0, 4), (1, 2, 1, 0), (1, 2, 1, 1), (1, 2, 1, 2), (1, 2, 1, 3), (1, 2, 1, 4), (1, 2, 2, 0), (1, 2, 2, 1), (1, 2, 2, 2), (1, 2, 2, 3), (1, 2, 2, 4), (1, 2, 3, 0), (1, 2, 3, 1), (1, 2, 3, 2), (1, 2, 3, 3), (1, 2, 3, 4)]

Upvotes: 1

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 96324

Use product from itertools:

In [3]: import itertools

In [4]: dims = (2, 3, 4)

In [5]: for idx in itertools.product(*map(range, dims)):
    ...:     print(idx)
    ...:
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 0, 3)
(0, 1, 0)
(0, 1, 1)
(0, 1, 2)
(0, 1, 3)
(0, 2, 0)
(0, 2, 1)
(0, 2, 2)
(0, 2, 3)
(1, 0, 0)
(1, 0, 1)
(1, 0, 2)
(1, 0, 3)
(1, 1, 0)
(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 2, 0)
(1, 2, 1)
(1, 2, 2)
(1, 2, 3)

As for dealing with the strings, there are many ways. Here is a quick and dirty way:

In [6]: def block_me(n):
    ...:     return "[" + str(n) + "]"
    ...:

In [7]: for idx in itertools.product(*map(range, dims)):
    ...:     print("".join([block_me(i) for i in idx]))
    ...:
[0][0][0]
[0][0][1]
[0][0][2]
[0][0][3]
[0][1][0]
[0][1][1]
[0][1][2]
[0][1][3]
[0][2][0]
[0][2][1]
[0][2][2]
[0][2][3]
[1][0][0]
[1][0][1]
[1][0][2]
[1][0][3]
[1][1][0]
[1][1][1]
[1][1][2]
[1][1][3]
[1][2][0]
[1][2][1]
[1][2][2]
[1][2][3]

Upvotes: 1

Related Questions