Controllo di flusso - cicli while

Scarica zip esercizi

Naviga file online

Vediamo come ripetere delle istruzioni eseguendole all’interno dei cicli while.

La caratteristica principale del ciclo while è che permette di controllare esplicitamente la condizione di fine del ciclo. Tipicamente, si utilizzano questi cicli quando si deve iterare su una sequenza la cui dimensione non è nota a priori, varia nel tempo oppure vi sono diverse condizioni che potrebbero determinare la fine del ciclo.

Referimenti:

Che fare

  • scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere:

control-flow
    flow1-if.ipynb
    flow1-if-sol.ipynb
    flow2-for.ipynb
    flow2-for-sol.ipynb
    flow3-while.ipynb
    flow3-while-sol.ipynb
    jupman.py

ATTENZIONE: Per essere visualizzato correttamente, il file del notebook DEVE essere nella cartella szippata.

  • apri il Jupyter Notebook da quella cartella. Due cose dovrebbero aprirsi, prima una console e poi un browser. Il browser dovrebbe mostrare una lista di file: naviga la lista e apri il notebook flow3-while.ipynb

  • Prosegui leggendo il file degli esercizi, ogni tanto al suo interno troverai delle scritte ESERCIZIO, che ti chiederanno di scrivere dei comandi Python nelle celle successive. Gli esercizi sono graduati per difficoltà, da una stellina ✪ a quattro ✪✪✪✪

Scorciatoie da tastiera:

  • Per eseguire il codice Python dentro una cella di Jupyter, premi Control+Invio

  • Per eseguire il codice Python dentro una cella di Jupyter E selezionare la cella seguente, premi Shift+Invio

  • Per eseguire il codice Python dentro una cella di Jupyter E creare una nuova cella subito dopo, premi Alt+Invio

  • Se per caso il Notebook sembra inchiodato, prova a selezionare Kernel -> Restart

Introduzione

Un ciclo while è un blocco di codice che viene eseguito quando si verifica una certa condizione booleana. Il blocco di codice viene ripetutamente eseguito fintantochè la condizione è vera.

Vediamo un esempio:

[2]:
i = 1

while i < 4:
    print('Ho contato fino a', i)
    i += 1

print('Ciclo finito !')
Ho contato fino a 1
Ho contato fino a 2
Ho contato fino a 3
Ciclo finito !

Nell’esempio, la condizione booleana è

i < 4

mentre il blocco di codice da eseguire ripetutamente è

print('Ho contato fino a', i)
i += 1

Come in tutti blocchi di codice Python, il blocco va indentato con gli spazi (di solito 4).

Guarda meglio l’esecuzione in Python Tutor e leggi il commento che segue.

[3]:
# AFFINCHE' PYTHON TUTOR FUNZIONI, RICORDATI DI ESEGUIRE QUESTA CELLA con Shift+Invio
#   (basta eseguirla una volta sola, la trovi anche all'inizio di ogni foglio)

import jupman
[4]:
i = 1
while i < 4:
    print('Ho contato fino a', i)
    i += 1

print('Ciclo finito !')

jupman.pytut()
Ho contato fino a 1
Ho contato fino a 2
Ho contato fino a 3
Ciclo finito !
[4]:

Nell’esempio abbiamo usato una variabile che abbiamo chiamato i e l’abbiamo inizializzata a zero.

All’inizio del ciclo i vale 1, perciò l’espressione booleana i < 4 viene valutata come True. Dato che è True, l’esecuzione procede all’interno del blocco con la print e infine MODIFICA i con l’incremento i += 1.

A questo punto l’esecuzione riprende alla riga del while, e la condizione i < 4 viene valutata di nuovo. A questa seconda iterazione i vale 2 perciò l’espressione booleana i < 4 viene ancora valutata a True e l’esecuzione rimane all’interno del blocco. Di nuovo, viene fatta la stampa con la print e incrementata i.

Viene fatto ancora un’altro ciclo finchè i vale 4. A quel punto i < 4 produce False e in quel momento l’esecuzione esce dal blocco while e prosegue con i comandi allo stesso livello di indentazione del while

while che terminano

Quando abbiamo un ciclo while, tipicamente vogliamo che prima o poi termini (i programmi che ‘si impallano’ non sono molto graditi agli utenti …). Per garantire la terminazione, abbiamo bisogno di:

  1. inizializzare una variabile all’esterno del ciclo

  2. una condizione dopo la scritta while che valuta quella variabile (e opzionalmente altro)

  3. almeno una istruzione nel blocco interno che MODIFICA la variabile, portandola prima o poi a soddisfare la condizione 2

Se uno qualsiasi di questi punti viene omesso, avremo problemi. Proviamo di proposito a dimenticarci di rispettarli:

Errore 1: omettere l’inizializzazione. Come in tutti i casi in Python in cui ci si è dimenticati di inizializzare una variabile (proviamo in questo caso j), l’esecuzione si interrompe non appena si cerca di usare la variabile:

print('Sto per entrare nel ciclo ..')
while j < 4:
    print('Ho contato fino a', j)
    j += 1

print('Ciclo finito !')
Sto per entrare nel ciclo ..
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-277-3f311955204d> in <module>()
      1 print('Sto per entrare nel ciclo ..')
----> 2 while j < 4:
      3     print('Ho contato fino a', j)
      4     j += 1
      5

NameError: name 'j' is not defined

Errore 2: omettere di usare la variabile nella condizione. Se ci si dimentica di valutare la variabile, per esempio usandone per sbaglio un’altra (supponiamo x), il ciclo non terminerà mai:

i = 1
x = 1
print('Sto per entrare nel ciclo ..')
while x < 4:   # valuta x invece di i
    print('Ho contato fino a', i)
    i += 1

print('Ciclo finito !')
Sto per entrare nel ciclo ..
Ho contato fino a 1
Ho contato fino a 2
Ho contato fino a 3
Ho contato fino a 4
Ho contato fino a 5
Ho contato fino a 6
.
.

Errore 3: Omettere di MODIFICARE la variabile nel blocco interno. Se ci si dimentica di mettere almeno un’istruzione che MODIFICA la variabile usata nella condizione, quando la condizione viene valutata produrrà sempre lo stesso valore booleano False impedendo l’uscita dal ciclo:

i = 1
print('Sto per entrare nel ciclo ..')
while i < 4:
    print('Ho contato fino a', i)

print('Ciclo finito !')
Sto per entrare nel ciclo ..
Ho contato fino a 1
Ho contato fino a 1
Ho contato fino a 1
Ho contato fino a 1
Ho contato fino a 1
.
.

while che non terminano

DOMANDA: Riesci ad immaginare un programma che non deve terminare mai?

Mostra risposta

Domande

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. i = 0
    while i < 3:
    print(i)
    
  2. k = 0
    while k < 5:
        print(k)
        k + 1
    
  3. i = 0
    while i < 3:
        print(i)
    i += 1
    
  4. i = 0
    while False:
        print(i)
        i += 1
    print('Finito !')
    
  5. i = 0
    while i < 3:
        print(i)
        i += 1
    
  6. k = 0
    while k < 2
        print(i)
        k += 1
    
  7. i = 0
    while i < 3:
        print('GAM')
        i = i + 1
    
  8. while zanza < 2
        print('ZANZA')
        zanza += 1
    
  9. i = 0
    while False:
        print(i)
        i = i + 1
    print('DARK')
    
  10. i = 0
    while True:
        print(i)
        i = i + 1
    print('LIGHT')
    
  11. while 2 + 3:
        print('z')
    print('')
    
  12. i = 10
    while i > 0:
        if i > 5:
            print(i)
            i -= 1
    print('WAM')
    
  13. i = 10
    while i > 0:
        if i > 5:
            print(i)
        i -= 1
    print('MAW')
    
  14. import random
    x = 0
    while  x < 7:
        x = random.randint(1,10)
        print(x)
    
    print('LUCK')
    
  15. x,y = 0,0
    while x + y < 4:
        x += 1
        y += 1
        print(x,y)
    
  16. x,y = 0,3
    while x < y:
        print(x,y)
        x += 1
        y -= 1
    

Esercizi

Esercizio - stampari

✪ Scrivi del codice che in un ciclo while stampa tutti i numeri dispari da 1 a k

  • per k<1 non stampa nulla

Esempio - dati:

k = 5

dopo il tuo codice deve stampare:

1
3
5
Mostra soluzione
[5]:
k = 5   # 1 3 5
#k = 1  # 1
#k = 0  # non stampa

# scrivi qui


1
3
5

Esercizio - media

✪ Scrivi del codice che data una lista numeri, calcola la media dei valori della lista usando un while e la stampa.

  • se la lista è vuota, la media si suppone essere 0.0

  • NON usare la funzione sum

  • NON creare variabili che si chiamano sum (violerebbe il V Comandamento: non ridifinerai mai funzioni di sistema)

Esempio - data:

numeri = [8,6,5,9]

stampa

7.0
Mostra soluzione
[6]:
numeri = [8,6,5,9] # 7.0
#numeri = [3,1,2]  # 2.0
#numeri = []       # 0

# scrivi qui


7.0

Comandi break e continue

Per avere ancora più controllo sull’esecuzione di un ciclo possiamo usare i comandi break e continue .

NOTA: Cerca di limitarne l’uso!

Quando vi è molto codice nel ciclo è facile ‘dimenticarsi’ della loro presenza trovandosi con bug difficili da scovare. D’altro canto, in alcuni casi selezionati possono rendere il codice più leggibile, quindi come in tutte le cose vanno usati con giudizio.

Terminare con un break

Lo schema visto precedentemente per avere while terminanti è quello consigliato, ma se abbiamo una condizione che NON valuta la variabile che incrementiamo (come per esempio l’espressione costante True), come alternativa per uscire immediatamente dal ciclo si può usare il comando break:

[7]:
i = 1
while True:

    print('Ho contato fino a', i)

    if i > 3:
        print('break! Esco dal ciclo!')
        break
        print('Dopo il break')

    i += 1

print('Ciclo finito !')
Ho contato fino a 1
Ho contato fino a 2
Ho contato fino a 3
Ho contato fino a 4
break! Esco dal ciclo!
Ciclo finito !

Nota come Dopo il break non venga mostrato.

Proseguire con continue

E’ possibile portare l’esecuzione immediatamente all’iterazione successiva chiamando continue, che salta subito alla verifica della condizione senza eseguire le istruzioni dopo il continue.

ATTENZIONE: i continue se usati male possono creare cicli infiniti !

Quando usi continue assicurati che non salti l’istruzione per modificare la varibile usata nella condizione di terminazione (oppure che non salti un break necessario per uscire)!

Per evitare problemi qui abbiamo incrementato i prima dell’if con il continue:

[8]:
i = 1
while i < 5:
    print('Ho contato fino a', i)

    i += 1

    if i % 2 == 1:
        print('continue, salta alla verifica condizione')
        continue
        print('Dopo il continue')

    print('arrivato in fondo')

print('Ciclo finito !')
Ho contato fino a 1
arrivato in fondo
Ho contato fino a 2
continue, salta alla verifica condizione
Ho contato fino a 3
arrivato in fondo
Ho contato fino a 4
continue, salta alla verifica condizione
Ciclo finito !

Proviamo a combinare break e continue e vedere il risultato in Python Tutor:

[9]:
i = 1
while i < 5:
    print('Ho contato fino a', i)
    if i > 3:
        print('break! Esco dal ciclo!')
        break
        print('Dopo il break')
    i += 1
    if i % 2 == 1:
        print('continue, salta alla verifica condizione')
        continue
        print('Dopo il continue')
    print('arrivato in fondo')

print('Ciclo finito !')

jupman.pytut()
Ho contato fino a 1
arrivato in fondo
Ho contato fino a 2
continue, salta alla verifica condizione
Ho contato fino a 3
arrivato in fondo
Ho contato fino a 4
break! Esco dal ciclo!
Ciclo finito !
[9]:

Domande su break e continue

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. i = 1
    while i < 4:
        print('Ho contato fino a', i)
        i += 1
        continue
    
    print('Ciclo finito !')
    
  2. i = 1
    while i < 4:
        print('Ho contato fino a', i)
        continue
        i += 1
    
    print('Ciclo finito !')
    
  3. i = 3
    while i > 0:
        print('Ho contato fino a', i)
        if i == 2:
            print('continue, salta alla verifica condizione')
            continue
        i -= 1
        print('arrivato in fondo')
    
    print('Ciclo finito !')
    
  4. i = 0
    while True:
        i += 1
        print(i)
        if i > 3:
            break
    
    print('BONG')
    
  5. i = 0
    while True:
        if i < 3:
            continue
        else:
            break
        i += 1
    
    print('ZONG')
    
  6. i = 0
    while True:
        i += 1
        if i < 3:
            continue
        else:
            break
    
    print('ZANG')
    

Esercizio - cercacar

✪✪ Scrivi del codice che usando un while che cerca nella lista di caratteri la il carattere indicato dalla variabile car . Nel momento in cui trova la PRIMA occorrenza del carattere, si ferma e stampa l’indice in cui è stato trovato.

  • se non trova il carattere, stampa che la ricerca è andata a vuoto.

Esempio 1 - dati:

car = 'z'
la = ['b','a','f','g','z','h','z','r']

dopo il tuo codice deve stampare

Trovato il primo z all'indice 4

Esempio 2 - dati:

car = 'z'
la = ['b','a','f','g','h','r']

deve stampare

Non ho trovato z
Mostra soluzione
[10]:
# scrivi qui


Trovato il primo z all'indice 4

Domande - Sono equivalenti ?

Guarda i seguenti frammenti di codice: in ciascuno, vi sono due parti, A e B. In ciascun frammento, cerca di indovinare se la parte A stamperà esattamente quello che stampa il codice nella parte B.

  • PRIMA pensa alla risposta

  • POI prova ad eseguire

Sono equivalenti? - BORG

print('A:')
while True:
    print('BORG')
    break

print('\nB:')
while False:
    pass
print('BORG')

Sono equivalenti? - al 3

print('A:')
x = 0
while x < 3:
    print(x)
    x += 1

print('\nB:')
x = 1
while x <= 3:
    print(x-1)
    x += 1

Sono equivalenti? - che caso

Ricordati che randint(a, b) restituisce un intero casuale N tale che a <= N <= b

print('A:')
x = 0
while x < 3:
    x += 1
print(x)

print('\nB:')
x = 0
import random
while x != 3:
    x = random.randint(1,5)
print(x)

Sono equivalenti? - al sei

print('A:')
i = 0
while i < 3:
    print(i)
    i += 1
while i < 6:
    print(i)
    i += 1

print('\nB:')
i = 0
while i < 6:
    print(i)
    i += 1

Sono equivalenti? - countdown 1

print('A:')
i = 2
print(i)
while i > 0:
    i -= 1
    print(i)

print('\nB:')
i = 2
while i > 0:
    print(i)
    i -= 1

Sono equivalenti? - countdown 2

print('A:')
i = 2
print(i)
while i > 0:
    i -= 1
    print(i)

print('\nB:')
i = 2
while i > 0:
    print(i)
    i -= 1
print(i)

Sono equivalenti? - sortilegio

print('A:')
s = 'sortilegio'
i = 0
while s[i] != 'g':
    i += 1
print(s[i:])

print('B:')
s = 'sortilegio'
i = len(s)
while s[i] != 'g':
    i -= 1
print(s[i:])

Sono equivalenti? - ping pong

print('A:')
ping,pong = 0,3
while ping < 3 or pong > 0:
    print(ping,pong)
    ping += 1
    pong -= 1

print('\nB:')
ping,pong = 0,3
while not(ping >= 3 and pong <= 0):
    print(ping,pong)
    ping += 1
    pong -= 1

Sono equivalenti? - zanna

print('A:')
n,i,s = 0,0,'zanna'
while i < len(s):
    if s[i] == 'n':
        n += 1
    i += 1
print(n)

print('\nB:')
n,i,s = 0,0,'zanna'
while i < len(s):
    i += 1
    if s[i-1] == 'n':
        n += 1
print(n)

Sono equivalenti? - pasticcio

print('A:')
c,i,s = 0,0,'pasticcio'
while i < len(s):
    if s[i] == 'c':
        c += 1
    i += 1
print(c)

print('\nB:')
no,k,s = 0,0,'pasticcio'
while k < len(s):
    if s[k] != 'c':
        no += 1
    else:
        k += 1
print(len(s) - no)

Esercizi su contatori

Esercizio - don’t break 1

✪ Guarda il codice seguente, e scrivi nella cella seguente del codice che produca lo stesso risultato con un while e senza usare break

[11]:
x = 3
while True:
    print(x)
    if x == 0:
        break
    x -= 1
3
2
1
0
Mostra soluzione
[12]:
x = 3

# scrivi qui


3
2
1
0

Esercizio - don’t break 2

✪ Guarda il codice seguente, e scrivi nella cella seguente del codice che produca lo stesso risultato con un while e senza usare break

[13]:
la = [2,3,7,5,6]
k = 7   # 2 3 7
#k = 5  # 2 3 7 5 6
#k = 13 # 2 3 7 5 6

i = 0
while True:
    print(la[i])
    if i >= len(la)-1 or la[i] == k:
        break
    else:
        i += 1
2
3
7
Mostra soluzione
[14]:
la = [2,3,7,5,6]
k = 7   # 2 3 7
#k = 6  # 2 3 7 5 6
#k = 13 # 2 3 7 5 6

i = 0

# scrivi qui


2
3
7

Esercizio - Dammi un break

✪ Guarda il codice seguente, e scrivi nella cella seguente del codice che produca lo stesso risultato con un while questa volta usando un break

[15]:

x,y = 1,5    # (1,5)  (2,4)
#x,y = 2,8   # (2, 8) (3, 7) (4, 6)

while x < y or x == 4:
    print((x,y))
    x += 1
    y -= 1
(1, 5)
(2, 4)
Mostra soluzione
[16]:
x,y = 1,5    # (1,5)  (2,4)
#x,y = 2,8   # (2, 8) (3, 7) (4, 6)

# scrivi qui


(1, 5)
(2, 4)

Esercizio - cartone

✪ Stampa numeri interi da 0 a k INCLUSI usando un while, e ad ogni numero stampa a fianco una tra le stringhe 'CAR', 'TO' e 'NE' alternandole

Es - per k=8 stampa

0 CAR
1 TO
2 NE
3 CAR
4 TO
5 NE
6 CAR
7 TO
8 NE
Mostra soluzione
[17]:
k = 8

# scrivi qui


0 CAR
1 TO
2 NE
3 CAR
4 TO
5 NE
6 CAR
7 TO
8 NE

Esercizio - al dieci

✪ Dati due numeri x e y, scrivi del codice con un while che stampa i numeri e li incrementa fermandosi non appena uno dei due raggiunge il dieci.

x,y = 5,7

dopo il tuo codice deve risultare

5 7
6 8
7 9
8 10
Mostra soluzione
[18]:
x,y = 5,7
#x,y = 8,4

# scrivi qui


5 7
6 8
7 9
8 10

Esercizio - cccc

✪ Scrivi del codice usando un while che dato un numero y, stampa y righe contenti la lettera c tante volte quante il numero di riga.

Esempio - dato

y = 4

Stampa:

c
cc
ccc
cccc
Mostra soluzione
[19]:

y = 4

# scrivi qui



c
cc
ccc
cccc

Esercizio - convergi

✪ Dati due numeri x e k, usando un while modifica di 1 e stampa x finchè x non raggiunge k incluso.

  • NOTA: k può essere sia maggiore che minore di x, devi gestire entrambi i casi

Esempio 1 - dato:

x,k = 3,5

stampa:

3
4
5

Esempio 2 - dato:

x,k = 6,2

stampa:

6
5
4
3
2
Mostra soluzione
[20]:

x,k = 3,5    # 3 4 5
#x,k = 6,2    # 6 5 4 3 2
#x,k = 4,4   # 4

# scrivi qui


3
4
5

Esercizio - wow

✪ Data una lista la di stringhe, scrivere del codice che cerca con un while all’interno della lista la prima occorrenza di una stringa che inizi con la lettera w (per esempio 'wow'. Appena la trova, il programma si ferma e stampa Trovata wow. Altrimenti, stampa Niente !.

Esempio 1 - data:

la = ['a','d','g','wow','f','wonder','r']

Stampa:

esaminato a
esaminato d
esaminato g
Trovato wow

Esempio 2 - data:

la = ['d','v','q','c','e']

stampa

esaminato d
esaminato v
esaminato q
esaminato c
esaminato e
Niente !
Mostra soluzione
[21]:
la = ['a','d','g','wow','f','wonder','r']    # a d g Trovato wow
#la = ['a','d','g','f','wonder','r', 'woman']  # a d g f Trovato wonder
#la = ['d','v','q','c','e']                    # d v q c e Niente !

# scrivi qui


esaminato a
esaminato d
esaminato g
Trovato wow

Esercizio - Wild West

✪✪ I due banditi Carson e Butch hanno sepolto di comune accordo un tesoro nella ridente cittadina di Tombstone, ma adesso ciascuno dei due vuole riprenderselo senza condividere nulla con il compare.

  • Per arrivare al tesoro c’è una strada da Santa Fe fino a Tombstone che rappresentiamo come lista di stringhe

  • per rappresentare dove sono i banditi nella strada, usiamo due indici butch e carson

  • ciascun bandito parte da una città diversa

  • ad ogni turno Carson si sposta di una città

  • ad ogni turno Butch si sposta di due città, perchè dispone di un veloce cavallo Mustang

Scrivi del codice che stampa la corsa e termina non appena uno dei due arriva nell’ultima città, indicando chi ha preso il tesoro.

  • Nel caso entrambi i banditi arrivino contemporaneamente nell’ultima città, stampa ‘Duello finale a Tombstone!’

  • il tuo codice deve funzionare per qualsiasi strada e posizioni iniziale carson e butch

Esempio 1 - dati

#             0         1          2              3            4               5
strada = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']
carson,butch  = 3, 0

deve stampare:

Carson parte da Silverton
Butch parte da Santa Fe
Carson raggiunge Agua Caliente
Butch raggiunge Dodge City
Carson raggiunge Tombstone
Butch raggiunge Agua Caliente

Carson ha trovato il tesoro a Tombstone !

Esempio 2 - dati

strada = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']
carson,butch  = 3, 2

deve stampare:

Carson parte da Silverton
Butch parte da Dodge City
Carson raggiunge Agua Caliente
Butch raggiunge Agua Caliente
Carson raggiunge Tombstone
Butch raggiunge Tombstone

Duello finale a  Tombstone !
Mostra soluzione
[22]:
#           0          1         2              3              4              5
strada = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']

carson,butch  = 3, 0    #  Carson ha trovato il tesoro a Tombstone !
#carson,butch  = 0, 0   #  Butch ha trovato il tesoro a Tombstone !
#carson,butch  = 3, 2   #  Duello finale a Tombstone !

# scrivi qui


Carson parte da Silverton
Butch parte da Santa Fe
Carson raggiunge Agua Caliente
Butch raggiunge Dodge City
Carson raggiunge Tombstone
Butch raggiunge Agua Caliente

Carson ha trovato il tesoro a Tombstone !

Modificare sequenze

Nel foglio sui cicli for abbiamo visto un importante avvertimento, che ripetiamo qua:

X COMANDAMENTO: Non aggiungerai o toglierai mai elementi da una sequenza che stai iterando con un for!

Abbandonarti in simil tentazioni produrrebbe comportamenti del tutto imprevedibili (conosci forse l’espressione volgare tirare il tappeto da sotto i piedi?)

Se proprio devi rimuovere elementi dalla sequenza su cui stai iterando, usa un ciclo while o effettua prima una copia della sequenza originale.

Nota che l’avviso è solo per i cicli for. In caso di necessità in fondo ci suggerisce di adottare come alternativa i while. Vediamo quindi quando e come usarli.

Stack - Pescare da mazzo di carte

Supponiamo di avere un mazzo di carte che rappresentiamo come lista di stringhe e vogliamo pescare tutte le carte, leggendole una per una

Possiamo scrivere un while che fintanto che il mazzo contiene carte, continua a togliere la carte in cima con il metodo pop e ne stampa il nome. Ricordati che pop MODIFICA la lista rimuovendo l’ultimo elemento E restituisce l’elemento come risultato della chiamata, che possiamo quindi salvare in una variabile che in questo caso chiameremo carta:

[23]:
mazzo = ['3 cuori',   # <---- in fondo
         '2 picche',
         '9 cuori',
         '5 quadri',
         '8 fiori']   # <---- in cima

while len(mazzo) > 0:
    carta = mazzo.pop()
    print('pescato', carta)

print('Finite le carte !')

jupman.pytut()
pescato 8 fiori
pescato 5 quadri
pescato 9 cuori
pescato 2 picche
pescato 3 cuori
Finite le carte !
[23]:

Guardando il codice, possiamo notare che:

  1. la variabile mazzo viene inizializzata

  2. si verifica che la dimensione di mazzo sia maggiore di zero

  3. ad ogni passo la lista mazzo viene MODIFICATA riducendone la dimensione

  4. ritorna al punto 2

I primi tre punti sono le condizioni che ci garantiscono che il while prima o poi terminerà,

Stack - Pescare fino a condizione

Supponiamo adesso di continuare a pescare carte finchè non ne troviamo una di cuori. La situazione è più complicata, perchè adesso il ciclo può terminare in due modi:

  1. troviamo cuori, e interrompiamo la ricerca

  2. non ci sono carte di cuori, e il mazzo si esaurisce

In ogni caso, alla fine dobbiamo riportare all’utente un risultato. A tal fine, ci risulta comodo inizializzare all’inizio la variabile carta come stringa vuota per gestire il caso non vengano trovate carte di cuori (o il mazzo sia vuoto).

Proviamo una prima implementazione che usa un if interno che verifica se abbiamo trovato cuori e in tal caso esce con il comando break.

  • Prova ad eseguire il codice togliendo il commento al secondo mazzo che non ha carte di cuori e guarda la differenza nell’esecuzione.

[24]:
mazzo = ['3 cuori','2 picche','9 cuori','5 quadri','8 fiori']
#mazzo = ['8 picche','2 picche','5 quadri','4 fiori']   # niente cuori !
carta = ''
while len(mazzo) > 0:
    carta = mazzo.pop()
    print('pescato', carta)
    if 'cuori' in carta:
        break

if 'cuori' in carta:
    print('Ho trovato cuori!')
else:
    print('Non ho trovato carte di cuori !')

jupman.pytut()
pescato 8 fiori
pescato 5 quadri
pescato 9 cuori
Ho trovato cuori!
[24]:

Esercizio - Don’t break my heart

✪ Prova a scrivere del codice che risolve lo stesso problema precedente:

  • questa volta NON usare il break

  • assicurati che il codice funzioni con un mazzo senza cuori e anche con un mazzo vuoto

  • SUGGERIMENTO: metti una condizione multipla nel while

Mostra soluzione
[25]:
mazzo = ['3 cuori','2 picche','9 cuori','5 quadri','8 fiori']
#mazzo = ['8 picche','2 picche','5 quadri','4 fiori']   # niente cuori !
#mazzo = []  # niente cuori !

carta = ''

# scrivi qui


pescato 8 fiori
pescato 5 quadri
pescato 9 cuori
Ho trovato cuori!

Domande - cosa fanno?

DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):

  1. while []:
        print('z')
    print('BIG')
    
  2. while ['a']:
        print('z')
    print('BUG')
    
  3. la = []
    while len(la) < 3:
        la.append('x')
    print(la)
    
  4. la = ['x','y','z']
    while len(la) > 0:
        print(la.pop())
    
  5. la = ['x','y','z']
    while la:
        print(la.pop(0))
    
  6. la = [4,5,8,10]
    while la.pop() % 2 == 0:
        print(la)
    

Domande - sono equivalenti?

Guarda i seguenti frammenti di codice: in ciascuno, vi sono due parti, A e B. In ciascun frammento, cerca di indovinare se la parte A stamperà esattamente quello che stampa il codice nella parte B.

  • PRIMA pensa alla risposta

  • POI prova ad eseguire

Sono equivalenti? - treno

print('A:')
la = ['t','r','e','n','o']
while len(la) > 0:
    print(la.pop())

print('\nB:')
la = ['t','r','e','n','o']
la.reverse()
while len(la) > 0:
    print(la.pop(0))

Sono equivalenti? - append nx

print('A:')
x,n,la = 2,0,[]
while x not in la:
    la.append(n)
    n += 1
print(la)

print('\nB:')
x,la = 2,[]
while len(la) < 3:
    la.append(x)
    x += 1
print(la)

Esercizi su stack

Esercizio - break somma

✪ Guarda il codice seguente, e riscrivilo nella cella seguente come while questa volta usando il comando break

[26]:

lista = []
i = 0
k = 10
while sum(lista) < k:
    lista.append(i)
    i += 1
    print(lista)
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
Mostra soluzione
[27]:
lista = []
i = 0

# scrivi qui


[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]

Esercizio - libri di viaggi

✪✪ Supponiamo di aver visitato la soffitta e raccolto una pila di libri, che rappresentiamo come lista di stringhe. Ogni stringa è preceduta da un etichetta di una lettera che indica la categoria (G per Giallo, V per Viaggi, S per Storia)

pila = ['S-Medioevo',   # <---- in fondo
        'V-Australia',
        'V-Scozia',
        'G-Sospetti',
        'V-Caraibi']    # <---- in cima

Essendo appassionati di libri di viaggi, vogliamo esaminare da pila un libro alla volta a partire da quello più in alto, trasferendo in un’altra catasta inizialmente vuota che chiameremo viaggi solo i libri che iniziano con l’etichetta V come ('V-Australia')

viaggi = []

Scrivi del codice che produce la seguente stampa:

All'inizio:
    pila:   ['S-Medioevo', 'V-Australia', 'V-Scozia', 'G-Sospetti', 'V-Caraibi']
    viaggi: []
Preso V-Caraibi
    pila:   ['S-Medioevo', 'V-Australia', 'V-Scozia', 'G-Sospetti']
    viaggi: ['V-Caraibi']
Scartato G-Sospetti
    pila:   ['S-Medioevo', 'V-Australia', 'V-Scozia']
    viaggi: ['V-Caraibi']
Preso V-Scozia
    pila:   ['S-Medioevo', 'V-Australia']
    viaggi: ['V-Caraibi', 'V-Scozia']
Preso V-Australia
    pila:   ['S-Medioevo']
    viaggi: ['V-Caraibi', 'V-Scozia', 'V-Australia']
Scartato S-Medioevo
    pila:   []
    viaggi: ['V-Caraibi', 'V-Scozia', 'V-Australia']
  • I libri non di viaggi non ci interessano e andranno scartati.

  • Il tuo codice deve funzionare per qualunque lista viaggi

Mostra soluzione
[28]:
pila = ['S-Medioevo', 'V-Australia', 'V-Scozia', 'G-Sospetti', 'V-Caraibi']

viaggi = []

# scrivi qui


All'inizio:
    pila:   ['S-Medioevo', 'V-Australia', 'V-Scozia', 'G-Sospetti', 'V-Caraibi']
    viaggi: []
Preso V-Caraibi
    pila:   ['S-Medioevo', 'V-Australia', 'V-Scozia', 'G-Sospetti']
    viaggi: ['V-Caraibi']
Scartato G-Sospetti
    pila:   ['S-Medioevo', 'V-Australia', 'V-Scozia']
    viaggi: ['V-Caraibi']
Preso V-Scozia
    pila:   ['S-Medioevo', 'V-Australia']
    viaggi: ['V-Caraibi', 'V-Scozia']
Preso V-Australia
    pila:   ['S-Medioevo']
    viaggi: ['V-Caraibi', 'V-Scozia', 'V-Australia']
Scartato S-Medioevo
    pila:   []
    viaggi: ['V-Caraibi', 'V-Scozia', 'V-Australia']

Esercizio - BANG !

✪✪ Ci sono due pile di oggetti pila_dx e pila_sx che rappresentiamo come liste di stringhe. Un cowboy per passare il tempo decide di sparare agli oggetti in cima alle pile, alternando ad ogni sparo la pila. Il cowboy è abile e fa sempre centro, quindi ad ogni sparo la pila bersaglio decresce.

  • Supponi che gli oggetti in alto siano quelli in fondo alla lista

  • Per tenere conto di quale pila colpire, usiamo una variabile sparo che tiene all’interno il valore 'dx' oppure 'sx'

  • Dopo ogni sparo il cowboy se possibile cambierà pila, altrimenti continuerà a sparare alla stessa finchè non rimangono più oggetti

  • il tuo codice deve funzionare per qualsiasi pila e sparo iniziale

Esempio - dati:

pila_sx = ['cassa','stivale','ferro di cavallo','secchio']
pila_dx = ['bidone','sella','latta']
sparo = 'dx'

dopo il tuo codice, deve stampare

BANG! a destra:    latta
   pila_sx: ['cassa', 'stivale', 'ferro di cavallo', 'secchio']
   pila_dx: ['bidone', 'sella']
BANG! a sinistra:  secchio
   pila_sx: ['cassa', 'stivale', 'ferro di cavallo']
   pila_dx: ['bidone', 'sella']
BANG! a destra:    sella
   pila_sx: ['cassa', 'stivale', 'ferro di cavallo']
   pila_dx: ['bidone']
BANG! a sinistra:  ferro di cavallo
   pila_sx: ['cassa', 'stivale']
   pila_dx: ['bidone']
BANG! a destra:    bidone
   pila_sx: ['cassa', 'stivale']
   pila_dx: []
BANG! a sinistra:  stivale
   pila_sx: ['cassa']
   pila_dx: []
   pila_sx: ['cassa']
   pila_dx: []
BANG! a sinistra:  cassa
   pila_sx: []
   pila_dx: []
Mostra soluzione
[29]:
pila_sx = ['cassa','stivale','ferro di cavallo','secchio']
pila_dx = ['bidone','sella','latta']
sparo = 'dx'

# scrivi qui


BANG! a destra:    latta
   pila_sx: ['cassa', 'stivale', 'ferro di cavallo', 'secchio']
   pila_dx: ['bidone', 'sella']
BANG! a sinistra:  secchio
   pila_sx: ['cassa', 'stivale', 'ferro di cavallo']
   pila_dx: ['bidone', 'sella']
BANG! a destra:    sella
   pila_sx: ['cassa', 'stivale', 'ferro di cavallo']
   pila_dx: ['bidone']
BANG! a sinistra:  ferro di cavallo
   pila_sx: ['cassa', 'stivale']
   pila_dx: ['bidone']
BANG! a destra:    bidone
   pila_sx: ['cassa', 'stivale']
   pila_dx: []
BANG! a sinistra:  stivale
   pila_sx: ['cassa']
   pila_dx: []
   pila_sx: ['cassa']
   pila_dx: []
BANG! a sinistra:  cassa
   pila_sx: []
   pila_dx: []

Esercizio - Crescere o decrescere ?

✪✪ Scrivi del codice che data una lista la, MODIFICA continuamente la lista secondo questa procedura:

  • se l’ultimo elemento è dispari (es 7), attacca alla fine della lista un nuovo numero ottenuto moltiplicando per due l’ultimo elemento (es. attacca 14)

  • se l’ultimo elemento è pari, toglie gli ultimi due elementi

  • NOTA 1: vogliamo proprio MODIFICARE la lista originale, NON vogliamo creare una nuova lista (quindi non vi saranno righe che iniziano con la =

  • NOTA 2: quando vogliamo far sia crescere che decrescere la sequenza che stiamo considerando in un ciclo, dobbiamo convincerci per bene che prima o poi la condizione di terminazione si verifichi, è facile sbagliarsi e finire con un ciclo infinito !

  • SUGGERIMENTO: per far decrescere la lista, puoi usare il metodo pop

Esempio - data:

la = [3,5,6,7]

eseguendo il tuo codice, deve stampare

Dispari: attacco 14
         la diventa [3, 5, 6, 7, 14]
   Pari: tolgo 14
         tolgo 7
         la diventa [3, 5, 6]
   Pari: tolgo 6
         tolgo 5
         la diventa [3]
Dispari: attacco 6
         la diventa [3, 6]
   Pari: tolgo 6
         tolgo 3
         la diventa []
Finito! la è []
Mostra soluzione
[30]:
la = [3,5,6,7]

# scrivi qui


Dispari: attacco 14
         la diventa [3, 5, 6, 7, 14]
   Pari: tolgo 14
         tolgo 7
         la diventa [3, 5, 6]
   Pari: tolgo 6
         tolgo 5
         la diventa [3]
Dispari: attacco 6
         la diventa [3, 6]
   Pari: tolgo 6
         tolgo 3
         la diventa []
Finito! la è []