Linea singola annidata per loop


102

Ha scritto questa funzione in Python che traspone una matrice:

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) ]

Nel processo mi sono reso conto che non capisco appieno come vengono eseguiti i loop annidati per singola riga. Per favore aiutami a capire rispondendo alle seguenti domande:

  1. Qual è l'ordine in cui viene eseguito questo ciclo for?
  2. Se avessi un triplo ciclo for annidato, quale ordine verrebbe eseguito?
  3. Cosa sarebbe uguale al ciclo for non testato uguale?

Dato,

[ function(i,j) for i,j in object ]
  1. Che tipo deve essere l'oggetto per poter utilizzare questo per la struttura del ciclo?
  2. Qual è l'ordine in cui i e j sono assegnati agli elementi in oggetto?
  3. Può essere simulato da una diversa struttura per loop?
  4. Può questo ciclo for essere annidato con una struttura simile o diversa per ciclo? E come sarebbe?

Sono apprezzate anche ulteriori informazioni.

Risposte:


169

La migliore fonte di informazioni è il tutorial ufficiale di Python sulla comprensione delle liste . Le comprensioni di lista sono quasi le stesse dei cicli for (certamente qualsiasi comprensione di lista può essere scritta come un ciclo for) ma sono spesso più veloci rispetto all'uso di un ciclo for.

Guarda questa comprensione della lista più lunga dal tutorial (la ifparte filtra la comprensione, solo le parti che passano l'istruzione if vengono passate nella parte finale della comprensione della lista (qui (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)]

È esattamente lo stesso di questo ciclo for annidato (e, come dice il tutorial, nota come l'ordine di for e if sono gli stessi).

>>> 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 principale differenza tra una comprensione della lista e un ciclo for è che la parte finale del ciclo for (dove si fa qualcosa) arriva all'inizio piuttosto che alla fine.

Alle tue domande:

Che tipo deve essere l'oggetto per poter utilizzare questo per la struttura del ciclo?

Un iterabile . Qualsiasi oggetto in grado di generare un insieme (finito) di elementi. Questi includono qualsiasi contenitore, elenco, set, generatore, ecc.

Qual è l'ordine in cui i e j sono assegnati agli elementi in oggetto?

Sono assegnati esattamente nello stesso ordine in cui sono generati da ciascuna lista, come se fossero in un ciclo for annidato (per la tua prima comprensione otterrai 1 elemento per i, quindi ogni valore da j, secondo elemento in i, quindi ogni valore da j, ecc.)

Può essere simulato da una diversa struttura per loop?

Sì, già mostrato sopra.

Può questo ciclo for essere annidato con una struttura simile o diversa per ciclo? E come sarebbe?

Certo, ma non è una grande idea. Qui, ad esempio, ti offre un elenco di elenchi di caratteri:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]

Mi chiedo cosa abbia guidato la loro scelta di ordinare nel doppio annidamento. Trovo il contrario più naturale (per y poi per x nel tuo esempio). Mi rendo conto che dopo 3 anni di utilizzo di Python (non ampiamente ma comunque ...) e di utilizzo di quel tipo di loop !!
Thomas,

@ Thomas trovo anche l'altro modo più intuitivo. La scelta credo sia stata puramente di convenienza. Farlo nel modo più intuitivo significherebbe avere a che fare con simboli irrisolti fino a quando non li troverà più avanti nell'istruzione. Prova ad analizzare ogni banana.peel in ogni banana per ogni city.bananastore in ogni città su carta. Non così facile. Il contrario però, piacevole e facile.
Pyjong

29

Potrebbe interessarti itertools.product, che restituisce un iterabile che restituisce tuple di valori da tutti gli iterabili che gli passi. Cioè, itertools.product(A, B)restituisce tutti i valori del modulo (a, b), da dove aprovengono Ai bvalori e da cui provengono B. Per esempio:

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)]

Questo stampa:

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

Notare come l'ultimo argomento passato a itertools.productè quello "interno". In generale, è uguale aitertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]


4

Prima di tutto, il tuo primo codice non usa un ciclo for di per sé, ma una comprensione di liste .

  1. Sarebbe equivalente a

    per j nell'intervallo (0, larghezza): per i nell'intervallo (0, altezza): m [i] [j]

  2. Più o meno allo stesso modo, generalmente si annida come i cicli for, da destra a sinistra. Ma la sintassi della comprensione delle liste è più complessa.

  3. Non sono sicuro di cosa stia chiedendo questa domanda


  1. Qualsiasi oggetto iterabile che produce oggetti iterabili che producono esattamente due oggetti (che boccone - cioè [(1,2),'ab']sarebbe valido)

  2. L'ordine in cui l'oggetto cede all'iterazione. iva alla prima resa, jalla seconda.

  3. Sì, ma non così carino. Credo che sia funzionalmente equivalente a:

    l = elenco ()
    per i, j in oggetto:
        l.append (funzione (i, j))
    

    o ancora meglio usa la mappa :

    map(function, object)

    Ma, naturalmente, la funzione avrebbe dovuto ottenere i, jper sé.

  4. Non è la stessa domanda di 3?


2

È possibile utilizzare due cicli for nella stessa riga utilizzando zipfunction

Codice:

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)

Produzione:

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

Quindi, usando la funzione zip, possiamo usare due cicli for o possiamo iterare due elenchi nella stessa riga.


-1

Di seguito il codice per i migliori esempi di cicli nidificati, mentre si utilizzano due cicli for, ricordare che l'output del primo ciclo è l'input per il secondo ciclo. Anche la terminazione del loop è importante durante l'utilizzo dei loop annidati

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.