magnetar
magnetar

Reputation: 6577

Using a Python list comprehension a bit like a zip

Ok, so I'm really bad at writing Python list comprehensions with more than one "for," but I want to get better at it. I want to know for sure whether or not the line

>>> [S[j]+str(i) for i in range(1,11) for j in range(3) for S in "ABCD"]

can be amended to return something like ["A1","B1","C1","D1","A2","B2","C2","D2"...(etc.)]

and if not, if there is a list comprehension that can return the same list, namely, a list of strings of all of the combinations of "ABCD" and the numbers from 1 to 10.

Upvotes: 4

Views: 388

Answers (5)

Lucas Ribeiro
Lucas Ribeiro

Reputation: 6282

EVERY time you think in combining all the elements if a iterable with all the elements of another iterable, think itertools.product. It is a cartesian product of two sets (or lists).

I've found a solution that is slightly more fast than the ones presented here until now. And more than 2x fast than @daniel solution (Although his solution looks far more elegant):

import itertools
[x + y for (x,y) in (itertools.product('ABCD', map(str,range(1,5))))]

The difference here is that I casted the int to strings using map. Applying functions over vectors is usually faster than applying them on individual items.

And a general tip when dealing with complex comprehensions:

When you have lots of for and lots of conditionals inside your comprehension, break it into several lines, like this:

[S[j]+str(i) for i in range(1,11)
             for j in range(3) 
             for S in "ABCD"]

In this case the change in easyness to read wasn't so big, but, when you have lots of conditionals and lots of fors, it makes a big diference. It's exactly like writing for loops and if statements nested, but without the ":" and the identation.

See the code using regular fors:

ans = []
for i in range(1,11):
    for j in range(3): 
        for S in "ABCD": 
            ans.append(S[j] + str(i))

Almost the same thing :)

Upvotes: 1

thefourtheye
thefourtheye

Reputation: 239453

You may use itertools.product like this

import itertools
print [item[1] + str(item[0]) for item in itertools.product(range(1, 11),"ABCD")]

Output

['A1', 'B1', 'C1', 'D1', 'A2', 'B2', 'C2', 'D2', 'A3', 'B3', 'C3', 'D3', 'A4',
 'B4', 'C4', 'D4', 'A5', 'B5', 'C5', 'D5', 'A6', 'B6', 'C6', 'D6', 'A7', 'B7',
 'C7', 'D7', 'A8', 'B8', 'C8', 'D8', 'A9', 'B9', 'C9', 'D9', 'A10', 'B10', 'C10',
 'D10']

Upvotes: 1

Jack_of_All_Trades
Jack_of_All_Trades

Reputation: 11468

The way I like to see more than one for loop in list comprehension is like the nested loop. Treat the next for loop as the loop nested in the first one and that will make it whole lot easier. To add to Daniel's answer:

[S+str(i) for i in range(1,11)  for S in "ABCD"]

is nothing more than:

new_loop=[]
for i in range (1,11):
    for S in "ABCD:
         new_loop.append(S+str(i))

Upvotes: 1

jabaldonedo
jabaldonedo

Reputation: 26572

Why don't use itertools.product?

>>> import itertools
>>> [ i[0] + str(i[1]) for i in itertools.product('ABCD', range(1,5))]
 ['A1', 'A2', 'A3', 'A4', 'B1', 'B2', 'B3', 'B4', 'C1', 'C2', 'C3', 'C4', 'D1', 'D2', 'D3', 'D4']

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599560

You have too many loops there. You don't need j at all.

This does the trick:

[S+str(i) for i in range(1,11) for S in "ABCD"]

Upvotes: 7

Related Questions