2009-07-29 28 views
118

En Python que puede tener múltiples iteradores en una lista por comprensión, comoiteración doble en lista por comprensión

[(x,y) for x in a for y in b] 

para algunas secuencias de a y b adecuados. Soy consciente de la semántica de bucle anidado de las listas de comprensión de Python.

Mi pregunta es: ¿Puede un iterador en la comprensión referirse al otro? En otras palabras: ¿Podría tener algo como esto:

[x for x in a for a in b] 

donde el valor actual del bucle externo es el iterador del interior?

A modo de ejemplo, si tengo una lista anidada:

a=[[1,2],[3,4]] 

lo que sería la expresión lista por comprensión ser lograr este resultado:

[1,2,3,4] 

?? (Por favor, solo haga una lista de respuestas de comprensión, ya que esto es lo que quiero averiguar).

Respuesta

66

Gee, creo que encontré el awser: no me estaba preocupando lo suficiente sobre qué loop es interno y cuál es externo. La lista debe ser como la comprensión:

[x for b in a for x in b] 

para obtener el resultado deseado, y sí, un valor actual puede ser el iterador para la próxima :-) bucle. Perdón por el ruido.

+33

La sintaxis de comprensión de listas no es uno de los puntos brillantes de Python. –

+0

@Glenn Sí, se complica fácilmente por algo más que simples expresiones. – ThomasH

+0

Ew. No estoy seguro de que este sea el uso "habitual" para las listas de comprensión, pero es muy desafortunado que el encadenamiento sea tan desagradable en Python. –

101

Para responder a su pregunta con su propia sugerencia:

>>> [x for b in a for x in b] # Works fine 

Mientras que pidió respuestas lista de comprensión, permítanme señalar también la excelente itertools.chain():

>>> from itertools import chain 
>>> list(chain.from_iterable(a)) 
>>> list(chain(*a)) # If you're using python < 2.6 
16

Thomash tiene Ya agregué una buena respuesta, pero quiero mostrar lo que sucede:

>>> a = [[1, 2], [3, 4]] 
>>> [x for x in b for b in a] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'b' is not defined 

>>> [x for b in a for x in b] 
[1, 2, 3, 4] 
>>> [x for x in b for b in a] 
[3, 3, 4, 4] 

Supongo Python analiza la lista de comprensión de izquierda a derecha. Esto significa que el primer bucle for que se produce se ejecutará primero.

El segundo "problema" de esto es que b se "filtró" fuera de la lista de comprensión. Después de la primera lista exitosa de comprensión b == [3, 4].

+3

Punto de interés. Me sorprendió esto: 'x = 'hola';' '[x para x en xrange (1,5)];' 'imprimir x # x ahora es 4' – grinch

+2

Esta fuga fue corregida en Python 3: https : //stackoverflow.com/questions/4198906/python-list-comprehension-rebind-names-even-after-scope-of-comprehension-is-thi –

1

Siento que esto es más fácil de entender

[row[i] for row in a for i in range(len(a))] 

result: [1, 2, 3, 4] 
44

espero que esto ayude a alguien más ya a,b,x,y no tiene mucho sentido para mí! Supongamos que tiene un texto lleno de oraciones y quiere una matriz de palabras.

# Without list comprehension 
list_of_words = [] 
for sentence in text: 
    for word in sentence: 
     list_of_words.append(word) 
return list_of_words 

Me gusta pensar en la comprensión de la lista como código de estiramiento horizontalmente.

Trate dividirlo en:

# List Comprehension 
[word for sentence in text for word in sentence] 
+2

¡Explicación brillante! – nekomatic

13

Orden de iteradores puede parecer contrario a la intuición.

Tomemos, por ejemplo: [str(x) for i in range(3) for x in foo(i)]

Vamos a descomponerlo:

def foo(i): 
    return i, i + 0.5 

[str(x) 
    for i in range(3) 
     for x in foo(i) 
] 

# is same as 
for i in range(3): 
    for x in foo(i): 
     yield str(x) 
+1

¡Qué revelador! – nehemiah

+0

Según tengo entendido, la razón para esto es que "la primera iteración enumerada es la iteración más alta que se escribiría si la comprensión se escribiera como anidada para bucles". La razón por la cual esto es contrario a la intuición es que el bucle OUTER (más arriba si está escrito como bucles for anidados) aparece en el INTERIOR de la lista/dict entre corchetes (objeto comprendido). Por el contrario, el bucle INNER (el más interno cuando está escrito como bucles for-anidados) es precisamente el bucle más a la derecha en una comprensión, y es de esa manera aparece en el EXTERIOR de la comprensión. –

5

Si desea mantener la matriz multidimensional, uno debería nido de los soportes de matriz. vea el ejemplo a continuación donde se agrega uno a cada elemento.

>>> a = [[1, 2], [3, 4]] 

>>> [[col +1 for col in row] for row in a] 
[[2, 3], [4, 5]] 

>>> [col +1 for row in a for col in row] 
[2, 3, 4, 5] 
1

Además, se puede usar la misma variable para el miembro de la lista de entrada que en la actualidad se accede y para el elemento en el interior de esta persona. Sin embargo, esto incluso podría hacer que sea más (lista) incomprensible.

input = [[1, 2], [3, 4]] 
[x for x in input for x in x] 

Primera for x in input se evalúa, lo que lleva a una lista de miembros de la entrada, a continuación, Python camina a través de la segunda parte for x in x durante el cual el valor de x se sobrescribe con el elemento actual que está accediendo, a continuación, la primera x define lo que queremos devolver.