2

I am trying to create a list of 3D indexes in python. One way I can do is iterate over all the ids in nested loops and do as follows:

l = list()

for z in range(0, 2):
    for y in range(1, 5);
        for x in range(1, 10):
            l.append((x, y, z))

However, I remember there was a one liner way to do this but for the life of me I cannot figure it out. I tried something like:

l.append((x, y, z) for x in range(0, 10), for y in range(0, 10), for z in range(0, 2))

However, this resulted in a syntax error.

0

2 Answers 2

7

You meant to write:

l = [(x, y, z) for x in range(0, 10) for y in range(0, 10) for z in range(0, 2)]

The commas are not necessary after the range() calls and you can directly assign the result (a list) to the variable l.

Sign up to request clarification or add additional context in comments.

4 Comments

@Luca: if you intend to create a list then this approach is better because it avoids calling append() for every element that you wish to add to the list. This code will immediately create a list with the desired elements without explicitly appending the elements one by one.
@Luca: I would say readability is more important than performance in writing Python code if months later someone needs to come back to it. In that case, your nested loop looks much clearer. If performance is a concern, you should pick a compiled and strongly typed language.
@SimeonVisser: The list is still created element by element, but a list comp is a little faster than using explicit for loops because it uses a special LIST_APPEND bytecode which is a bit more efficient than doing a list.append() method call.
@Luca: If you're concerned about performance then use itertools.product, since it's written in C, and C code runs significantly faster than Python code. And as others have said, it's often better to use a generator that yields the items one by one rather than building a RAM-hogging list, unless you actually need the whole collection of items as a united entity for some reason (eg random access).
7

You are getting SyntaxError, because

(x, y, z) for x in range(0, 10), for y in range(0, 10), for z in range(0, 2)

you separate the for expressions with commas. But as per the grammar for list comprehension,

comprehension ::=  expression comp_for
comp_for      ::=  "for" target_list "in" or_test [comp_iter]
comp_iter     ::=  comp_for | comp_if
comp_if       ::=  "if" expression_nocond [comp_iter]

commas should not be there.

Now, even after removing the commas, your program will have a logic error

>>> l = []
>>> l.append((x, y, z) for x in range(10) for y in range(10) for z in range(2))
>>> l
[<generator object <genexpr> at 0x7f5b78302b40>]

Here, the expression (x, y, z) for x in range(0, 10) for y in range(0, 10) for z in range(0, 2) is treated as a generator expression. So, you need to create a list, with list function, like this

>>> list((x, y, z) for x in range(1) for y in range(2) for z in range(2))
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]

Instead, you can use list comprehension to create a new list, like this

>>> [(x, y, z) for x in range(1) for y in range(2) for z in range(2)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]

But, in this case, you can use itertools.product, as well

>>> from itertools import product
>>> list(product(range(1), range(2), range(2)))
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]

product function returns a generator, to get the actual entire list, we use list function.

PS: You don't have use the starting value in range function if it is zero, as that is the default value.

Note: What you are actually trying to do is called generating the cartesian product of three iterables. The result will have huge number of elements. So, unless you need all the elements at once, you can simply iterate the product's result. This will greatly improve the program's performance as the entire result need not have to computed immediately.

>>> for items in product(range(1), range(2), range(2)):
...     print(items)
...     
... 
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)

Now, the values are generated only during their respective iterations.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.