
Questo articolo descrive come interrompere i cicli nidificati in Python.
- Vieni a scrivere loop annidati in Python
- Rompi i loop nidificati con else e continua
- Rompi i cicli annidati con una variabile flag
- Evita i loop nidificati con itertools.product()
- Confronto di velocità
Vedere l’articolo seguente per l’utilizzo di base del ciclo per in Python.
Vieni a scrivere loop annidati in Python
In Python, i loop nidificati (loop multipli) sono scritti come segue. I blocchi sono rappresentati da rientri in Python, quindi aggiungi semplicemente più rientri.
l1 = [1, 2, 3]
l2 = [10, 20, 30]
for i in l1:
for j in l2:
print(i, j)
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# 2 30
# 3 10
# 3 20
# 3 30
Quando l’interruzione viene eseguita nel ciclo interno, esce solo dal ciclo interno e il ciclo esterno continua.
for i in l1:
for j in l2:
print(i, j)
if i == 2 and j == 20 :
print('BREAK')
break
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# BREAK
# 3 10
# 3 20
# 3 30
Rompi i loop nidificati con else e continua
Nel ciclo for di Python, puoi usare else e continuare oltre a break.
Puoi interrompere tutti i loop con else e continuare.
for i in l1:
for j in l2:
print(i, j)
if i == 2 and j == 20:
print('BREAK')
break
else:
continue
break
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# BREAK
Il codice con la spiegazione è il seguente.
for i in l1:
print('Start outer loop')
for j in l2:
print('--', i, j)
if i == 2 and j == 20:
print('-- BREAK inner loop')
break
else:
print('-- Finish inner loop without BREAK')
continue
print('BREAK outer loop')
break
# Start outer loop
# -- 1 10
# -- 1 20
# -- 1 30
# -- Finish inner loop without BREAK
# Start outer loop
# -- 2 10
# -- 2 20
# -- BREAK inner loop
# BREAK outer loop
Quando il ciclo interno termina normalmente senza interruzioni, viene eseguita la clausola else. Questa continua è per il ciclo esterno e salta l’interruzione nel ciclo esterno e continua al ciclo successivo.
Quando il ciclo interno termina con un’interruzione, continua nella clausola else non viene eseguita. In questo caso, viene eseguita l’interruzione nel ciclo esterno.
Di conseguenza, ogni volta che il ciclo interno termina con un’interruzione, viene eseguita anche l’interruzione nel ciclo esterno.
L’idea è la stessa anche se il numero di loop aumenta. Un esempio di un ciclo triplo è il seguente.
l1 = [1, 2, 3]
l2 = [10, 20, 30]
l3 = [100, 200, 300]
for i in l1:
for j in l2:
for k in l3:
print(i, j, k)
if i == 2 and j == 20 and k == 200:
print('BREAK')
break
else:
continue
break
else:
continue
break
# 1 10 100
# 1 10 200
# 1 10 300
# 1 20 100
# 1 20 200
# 1 20 300
# 1 30 100
# 1 30 200
# 1 30 300
# 2 10 100
# 2 10 200
# 2 10 300
# 2 20 100
# 2 20 200
# BREAK
Rompi i cicli annidati con una variabile flag
Il modo sopra di usare altrimenti e continuare può essere difficile da capire per chi non ha familiarità con Python.
L’aggiunta di una variabile flag può rendere il codice più facile da capire per molti.
Nella condizione che il ciclo interno termini con un’interruzione, imposta il flag su True e nel ciclo esterno, imposta l’interruzione in base al flag.
Doppio anello:
l1 = [1, 2, 3]
l2 = [10, 20, 30]
flag = False
for i in l1:
for j in l2:
print(i, j)
if i == 2 and j == 20:
flag = True
print('BREAK')
break
if flag:
break
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# BREAK
Triplo ciclo:
l1 = [1, 2, 3]
l2 = [10, 20, 30]
l3 = [100, 200, 300]
flag = False
for i in l1:
for j in l2:
for k in l3:
print(i, j, k)
if i == 2 and j == 20 and k == 200:
flag = True
print('BREAK')
break
if flag:
break
if flag:
break
# 1 10 100
# 1 10 200
# 1 10 300
# 1 20 100
# 1 20 200
# 1 20 300
# 1 30 100
# 1 30 200
# 1 30 300
# 2 10 100
# 2 10 200
# 2 10 300
# 2 20 100
# 2 20 200
# BREAK
Puoi evitare i loop nidificati con itertools.product().
Puoi utilizzare itertools.product() per ottenere tutte le combinazioni di più elenchi in un ciclo e ottenere lo stesso risultato dei cicli nidificati.
import itertools
l1 = [1, 2, 3]
l2 = [10, 20, 30]
for i, j in itertools.product(l1, l2):
print(i, j)
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# 2 30
# 3 10
# 3 20
# 3 30
Poiché si tratta di un singolo ciclo, puoi interromperlo nelle condizioni desiderate.
for i, j in itertools.product(l1, l2):
print(i, j)
if i == 2 and j == 20:
print('BREAK')
break
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# BREAK
Aggiungendo l’argomento di itertools.product(), puoi eseguire il processo corrispondente a più cicli multipli.
l1 = [1, 2, 3]
l2 = [10, 20, 30]
l3 = [100, 200, 300]
for i, j, k in itertools.product(l1, l2, l3):
print(i, j, k)
if i == 2 and j == 20 and k == 200:
print('BREAK')
break
# 1 10 100
# 1 10 200
# 1 10 300
# 1 20 100
# 1 20 200
# 1 20 300
# 1 30 100
# 1 30 200
# 1 30 300
# 2 10 100
# 2 10 200
# 2 10 300
# 2 20 100
# 2 20 200
# BREAK
Nota
In itertools.product(), il processo per l’elemento viene sempre eseguito per tutte le combinazioni.
Nell’esempio seguente, la moltiplicazione viene eseguita 9 volte sia per i che per j.
for i, j in itertools.product(l1, l2):
x = i * 2 + j * 3
print(i, j, x)
# 1 10 32
# 1 20 62
# 1 30 92
# 2 10 34
# 2 20 64
# 2 30 94
# 3 10 36
# 3 20 66
# 3 30 96
Nel caso di cicli annidati, il processo per il ciclo esterno viene eseguito dal numero di elementi esterni.
Nell’esempio seguente, la moltiplicazione per la variabile i è solo 3 volte.
for i in l1:
temp = i * 2
for j in l2:
x = temp + j * 3
print(i, j, x)
# 1 10 32
# 1 20 62
# 1 30 92
# 2 10 34
# 2 20 64
# 2 30 94
# 3 10 36
# 3 20 66
# 3 30 96
Confronto di velocità
Viene mostrato il risultato della misurazione del tempo di esecuzione di ogni modo con il comando magico %%timeit di Jupyter Notebook. Nota che non può essere misurato da eseguire come codice Python.
Si noti che i risultati differiranno a seconda del numero di elementi e del numero di cicli per da annidare.
Prendi un triplo ciclo con 100 elementi come esempio.
import itertools
n = 100
l1 = range(n)
l2 = range(n)
l3 = range(n)
x = n - 1
%%timeit
for i in l1:
for j in l2:
for k in l3:
if i == x and j == x and k == x:
break
else:
continue
break
else:
continue
break
# 43 ms ± 1.33 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
flag = False
for i in l1:
for j in l2:
for k in l3:
if i == x and j == x and k == x:
flag = True
break
if flag:
break
if flag:
break
# 45.2 ms ± 3.42 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
for i, j, k in itertools.product(l1, l2, l3):
if i == x and j == x and k == x:
break
# 55.8 ms ± 458 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
L’uso di else, continue e l’aggiunta di variabili flag sono più o meno equivalenti e itertools.product() è lento.
Tuttavia, in alcuni casi, itertools.product() è più adatto perché migliora la leggibilità del codice anche se è lento. Dovresti usare una seconda della situazione.
