Línea única anidada para bucles

102

Escribí esta función en python que transpone una matriz:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

En el proceso, me di cuenta de que no entiendo completamente cómo se ejecutan los bucles for anidados de una sola línea. Ayúdame a comprender respondiendo las siguientes preguntas:

  1. ¿Cuál es el orden en el que se ejecuta este bucle for?
  2. Si tuviera un bucle for anidado triple, ¿qué orden se ejecutaría?
  3. ¿Cuál sería igual al ciclo for igual no anidado?

Dado,

[ function(i,j) for i,j in object ]
  1. ¿Qué tipo debe ser el objeto para usar esto para la estructura de bucle?
  2. ¿Cuál es el orden en el que i y j se asignan a los elementos del objeto?
  3. ¿Puede ser simulado por una estructura de bucle for diferente?
  4. ¿Se puede anidar este bucle for con una estructura for bucle similar o diferente? ¿Y cómo se vería?

También se agradece la información adicional.

Asher Garland
fuente

Respuestas:

169

La mejor fuente de información es el tutorial oficial de Python sobre listas por comprensión . Las listas de comprensión son casi las mismas que las de los bucles for (ciertamente, cualquier comprensión de la lista se puede escribir como un bucle for) pero a menudo son más rápidas que usar un bucle for.

Mire esta lista de comprensión más larga del tutorial (la ifparte filtra la comprensión, solo las partes que pasan la instrucción if se pasan a la parte final de la comprensión de la lista (aquí (x,y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Es exactamente lo mismo que este bucle for anidado (y, como dice el tutorial, observe cómo el orden de for y if es el mismo).

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

La principal diferencia entre una lista de comprensión y un ciclo for es que la parte final del ciclo for (donde haces algo) viene al principio y no al final.

A tus preguntas:

¿Qué tipo debe ser el objeto para usar esto para la estructura de bucle?

Un iterable . Cualquier objeto que pueda generar un conjunto (finito) de elementos. Estos incluyen cualquier contenedor, listas, conjuntos, generadores, etc.

¿Cuál es el orden en el que i y j se asignan a los elementos del objeto?

Se asignan exactamente en el mismo orden en que se generan a partir de cada lista, como si estuvieran en un bucle for anidado (para su primera comprensión, obtendría 1 elemento para i, luego cada valor de j, segundo elemento en i, luego cada valor de j, etc.)

¿Puede ser simulado por una estructura de bucle for diferente?

Sí, ya se muestra arriba.

¿Se puede anidar este bucle for con una estructura for bucle similar o diferente? ¿Y cómo se vería?

Claro, pero no es una gran idea. Aquí, por ejemplo, le da una lista de listas de personajes:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]
Jeff Tratner
fuente
Me pregunto qué guió su elección de ordenar en el doble nido. Encuentro la otra forma más natural (para y luego para x en su ejemplo). Me doy cuenta de que después de 3 años de hacer Python (no mucho, pero aún así ...) y de usar ese tipo de bucles !!
Thomas
@Thomas También encuentro la otra forma más intuitiva. Creo que la elección fue puramente conveniente. Hacerlo de la manera más intuitiva significaría tener que lidiar con símbolos no resueltos hasta que los encontrara más adelante en la declaración. Trate de analizar cada plátano, la cáscara de cada plátano de cada ciudad, la tienda de plátanos de cada ciudad en papel. No es tan fácil. Sin embargo, al revés, agradable y fácil.
Pyjong
29

Es posible que le interese itertools.product, que devuelve un iterable que produce tuplas de valores de todos los iterables que le pasa. Es decir, itertools.product(A, B)produce todos los valores del formulario (a, b), de dónde aprovienen Alos bvalores y de dónde provienen los valores B. Por ejemplo:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

Esto imprime:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

Observe cómo el argumento final que se pasa itertools.productes el "interno". Generalmente, es igual aitertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]

Lynn
fuente
4

En primer lugar, su primer código no usa un bucle for per se, sino una lista de comprensión .

  1. Sería equivalente a

    para j en rango (0, ancho): para i en rango (0, altura): m [i] [j]

  2. De la misma manera, generalmente anida como bucles for, de derecha a izquierda. Pero la sintaxis de comprensión de listas es más compleja.

  3. No estoy seguro de lo que hace esta pregunta


  1. Cualquier objeto iterable que produzca objetos iterables que produzcan exactamente dos objetos (qué bocado, es decir [(1,2),'ab'], sería válido)

  2. El orden en el que el objeto cede tras la iteración. iva al primer rendimiento, jal segundo.

  3. Sí, pero no tan bonito. Creo que es funcionalmente equivalente a:

    l = lista ()
    para i, j en objeto:
        l.append (función (i, j))
    

    o incluso mejor usa el mapa :

    map(function, object)

    Pero, por supuesto, la función tendría que llegar i, jsí.

  4. ¿No es esta la misma pregunta que 3?

korylprince
fuente
2

Puede usar dos bucles for en la misma línea usando la zipfunción

Código:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

Salida:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

Entonces, al usar la función zip, podemos usar dos bucles for o podemos iterar dos listas en la misma fila.

Muhammad Abbas
fuente
-1

A continuación se muestra el código para obtener los mejores ejemplos de bucles anidados, mientras que utiliza dos bucles for, recuerde que la salida del primer bucle es la entrada para el segundo bucle. La terminación de bucle también es importante al utilizar los bucles anidados

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
rameshbabu reddy
fuente