Doble iteración en la comprensión de la lista

En Python puedes tener múltiples iteradores en una lista de comprensión, como

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

para algunas secuencias adecuadas ay b. Soy consciente de la semántica de bucle nested 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 interno?

Como ejemplo, si tengo una lista anidada:

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

¿Cuál sería la expresión de comprensión de lista para lograr este resultado?

 [1,2,3,4] 

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

Para responder a su pregunta con su propia sugerencia:

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

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

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

Caramba, creo que encontré la respuesta: no estaba cuidando lo suficiente sobre qué bucle es interno y cuál es externo. La lista de comprensión debe ser como:

 [x for b in a for x in b] 

para obtener el resultado deseado, y sí, un valor actual puede ser el iterador para el siguiente ciclo.

¡Espero que esto ayude a alguien más ya que a,b,x,y no tienen mucho significado para mí! Supongamos que tienes un texto lleno de oraciones y quieres una serie 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 listas como un código de estiramiento horizontal.

Intenta dividirlo en:

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

El orden de los iteradores puede parecer contraintuitivo.

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) 

ThomasH ya ha agregado 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 "", line 1, in  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 que 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 “filtra” fuera de la lista de comprensión. Después de la primera comprensión exitosa de la lista b == [3, 4] .

Si desea mantener la matriz multidimensional, debe anidar 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] 

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

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

Primero se evalúa la for x in input , lo que lleva a una lista de miembros de la entrada, luego, Python recorre la segunda parte for x in x durante la cual el valor actual se sobrescribe con el elemento actual al que está accediendo, luego la primera x define Lo que queremos volver.

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]