List Comprehension question
Francis Avila
francisgavila at yahoo.com
Wed Dec 10 22:54:27 EST 2003
Mark Elston wrote in message ...
>Anyway, I thought I was following the discussions of List
>Comprehension (LC) until I got to Recipe 1.16. In this recipe
>we have the following:
>
> arr = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]
> print [[r[col] for r in arr] for col in range(len(arr[0]))]
> -> [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
All the second line is saying, is, for every pass of the innermost (here,
rightmost) for-loop, execute this list comprehension: [r[col] for r in arr].
Same as:
res = []
for col in range(3):
res.append([r[col] for r in arr])
Unrolling a bit more:
res = []
for col in range(3):
innerres = []
for r in arr:
innerres.append(r[col])
res.append(innerres)
Note this is NOT the same as [r[col] for col in range(3) for r in arr]!
res = []
for col in range(3):
for r in arr:
res.append(r[col])
-> [1, 4, 7, 10, 2, 5, 8, 11, 3, 6, 9, 12]
See? It's flattened, because the list comp's expression evaluates to an
integer instead of a list.
>I thought I understood this until I got to the above recipe. Here
>it looks like the order of evaluation is reversed. That is, instead
>of translating to:
>
> for r[col] in arr:
> for col in range(len(arr[0])):
> ...
>
>we actually have
>
> for col in range(len(arr[0])):
> for r[col] in arr:
> ...
Nope. See above.
>While I don't really understand it I may have some kind of rationale.
>Please let me know if this is correct.
You're thinking too much. :)
> The expression, itself, is also a LC.
This is the part that's causing you confusion. This is a nested list comp:
for every iteration in the outer list comp, execute the expression. The
fact that the expression happens to be a list comp itself just means that
the outer list comp will append a new list on each pass.
Wrap the inner list comp in a function call and it will make sense to you:
def innercomp(col):
return [r[col] for r in arr]
[innercomp(col) for col in range(3)]
-> [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
(It's also significantly slower.)
>Well, hmmmmm. OK. Maybe I do understand it. It just wasn't apparent
>at first.
>
>Am I close, or did I guess wrong?
You got it.
Note, however, that the same thing is far easier with zip():
>>> zip(*arr)
[(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]
If you need the items to be lists,
>>> [list(i) for i in zip(*arr)]
[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
or,
>>> map(list, zip(*arr))
[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
--
Francis Avila
More information about the Python-list
mailing list