Cicli while 1 - introduzione

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.

Che fare

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

while
    while1.ipynb
    while1-sol.ipynb
    while2-chal.ipynb
    jupman.py

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

  1. 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 while1.ipynb

  2. 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.

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

Contare con un while

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]:
Python Tutor visualization

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

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

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]:
Python Tutor visualization

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

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

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

x = 3 # scrivi qui

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

[12]:
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
[13]:

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

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

[14]:

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
[15]:

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

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
[16]:

k = 8 # scrivi qui

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
[17]:

x,y = 5,7 #x,y = 8,4 # scrivi qui

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
[18]:

y = 4 # scrivi qui

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
[19]:

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

Ricercare in una sequenza

Siamo ad un aereoporto e ci viene detto di raggiungere il gate della nostra compagnia aerea di fiducia Turbolenz. Non ci ricordiamo esattamente il gate, ma sappiamo che dobbiamo fermarci al primo cartello Turbulenz che troviamo. Se per sbaglio proseguissimo oltre, potremmo finire ad altri gate per voli internazionali, e chissà dove ci porterebbero.

Se dobbiamo fare ricerche in sequenze potenzialmente molto lunghe sapendo, ma che non sempre richiedono di visitare tutta la sequenza, usare un ciclo while è più conveniente ed efficiente di un for.

Potremmo rappresentare l’esempio qua sopra come una lista:

[20]:
             #    0         1            2            3           4           5         6           7
aereoporto = ['Volatut','AliBucate','PiccionJet','Turbolenz', 'BoingBoing','Jettoni','Turbulenz','BoingBoing' ]

Una volta trovato l’elemento, vorremmo che il programma ci stampasse la posizione in cui l’ha trovato, in questo caso 3

Naturalmente, se hai letto bene i metodi delle liste saprai che già abbiamo a disposizione un comodo metodo .index('Turbulenz'), ma in questo foglio adottiamo invece la filosofia del ‘fai da te’ e proveremo a costruirci da zero i nostri algoritmi di ricerca.

DOMANDA: Riesci a pensare ad un caso in cui il metodo index possa dare dei problemi?

Mostra risposta

Per costruire la nostra ricerca, ci serviranno:

  1. variabile di controllo

  2. condizione di termine

  3. aggiornamento della variabile di controllo

La variabile di controllo in questo caso potrebbe essere un indice, la condizione di termine potrebbe valutare se abbiamo raggiunto la fine dell’aereoporto, e dentro il ciclo dovremo incrementare l’indice per progredire nella ricerca. Ma dove potremmo valutare se abbiamo trovato o meno il gate? Inoltre, visto che siamo programmatori esperti, crediamo nella sfortuna e sappiamo che potremmo anche scoprire con orrore che la compagnia aerea Turbulenz è fallita il giorno del nostro arrivo in aereoporto! Dovremo pertanto sempre prevedere anche il caso in cui la ricerca vada a vuoto, e decidere come dovrebbe comportarsi il programma in questo frangente.

Come controllare

Ci sono due modi per controllare il ritrovamento:

  1. il modo più diretto di fare un controllo di uscita è dentro il corpo stesso del while, mettendo un if che al verificarsi del ritrovamento provoca l’esecuzione di un break. Non è affatto elegante, ma può essere un primo approccio.

  2. un’opzione migliore è fare il controllo nella condizione booleana del while, ma potrebbe essere un po’ più difficile avere un programma che funziona davvero in tutti i casi.

Proviamoli entrambi i modi negli esercizi che seguono.

Esercizio - Turbolenz con break

✪✪ Scrivi del codice che usando un while cerca nella lista aereoporto la PRIMA occorrenza di compagnia: appena la trova si ferma e STAMPA l’indice in cui è stata trovata.

  • se non trova la compagnia, STAMPA che la ricerca è andata a vuoto

  • USA un break per fermare la ricerca

  • RICORDATI di provare il tuo programma anche con gli altri aereoporti suggeriti

Esempio 1 - dati:

compagnia = 'Turbolenz'
aereoporto = ['Volatut','AliBucate','PiccionJet','Turbolenz', 'BoingBoing','Jettoni','Turbulenz','BoingBoing' ]

dopo il tuo codice deve stampare :

Trovato il primo Turbolenz all'indice 3

Esempio 2 - dati:

compagnia = 'FlapFlap'
aereoporto = ['AliBucate','BoingBoing','Turbolenz','PiccionJet']

deve stampare:

Non ho trovato FlapFlap
Mostra soluzione
[21]:


compagnia = 'Turbolenz' aereoporto = ['Volatut','AliBucate','PiccionJet','Turbolenz', 'BoingBoing','Jettoni','Turbulenz','BoingBoing'] #compagnia = 'FlapFlap' #aereoporto = ['AliBucate','BoingBoing','Turbolenz','PiccionJet'] #aereoporto = [] #aereoporto = ['FlapFlap'] #aereoporto = ['Turbolenz', 'FlapFlap'] # scrivi qui

Esercizio - Turbolenz senza break

✪✪ Prova adesso a riscrivere il programma di prima, ma NON usare breakcontinue: per verificare il ritrovamento, dovrai arricchire la condizione di terminazione.

Mostra soluzione
[22]:


compagnia = 'Turbolenz' aereoporto = ['Volatut','AliBucate','PiccionJet','Turbolenz', 'BoingBoing','Jettoni','Turbulenz','BoingBoing'] #compagnia = 'FlapFlap' #aereoporto = ['AliBucate','BoingBoing','Turbolenz','PiccionJet'] #aereoporto = [] #aereoporto = ['FlapFlap'] #aereoporto = ['Turbolenz', 'FlapFlap'] # scrivi qui

DOMANDA: Probabilmente hai usato due condizioni nel while. Scambiando l’ordine delle condizioni nella soluzione proposta, il programma funzionerebbe correttamente? Se no, in quali casi fallirebbe?

Mostra risposta

Esercizio - hangar

✪✪ Il nostro aereo è appena atterrato ma deve arrivare all’hangar schivando tutti gli oggetti estranei che trova sulla pista! Scrivi del codice che data una stringa pista con un certo numero di caratteri non alfanumerici all’inizio, STAMPA la parola che segue questi caratteri.

Esempio - data:

pista = '★★🏳🏳♦🏳♦🏳🏳hangar★★★'

il tuo codice deve stampare:

hangar★★★

  • NON puoi sapere a priori quali caratteri extra troverai nella stringa

  • NON scrivere caratteri come ★🏳♦-_ nel codice

SUGGERIMENTO: per determinare se hai trovato caratteri alfanumerici o numeri, usa i metodi .isalpha() e .isdigit()

Mostra soluzione
[23]:

pista = '★★🏳🏳♦🏳♦🏳🏳hangar★★★' # hangar★★★ #pista = '🏳🏳bimotore' # bimotore #pista = '-★♦--♦--747-🏳' # 747-🏳 #pista = 'aliante' # aliante #pista = '__♦__🏳__♦_' # non stampa niente # scrivi qui

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
[24]:

# 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

Esercizio - La Bilancia del Linguaggio

✪✪ Nei sacri scritti del profeta Zamfir, è predetto che qualora tutti gli abitanti della Terra parleranno una lingua in cui tutte le parole hanno la stessa lunghezza, sarà raggiunta l’armonia tra le umane genti. Questo evento è previdibilmente assai lontano nel tempo e per quell’epoca il vocabolario degli umani sarà talmente ampio e variegato che per controllare tutte le parole serviranno certamente potenti calcoli: ti viene richiesto di programmare i server subacquei di Atlantis per effettuare questo controllo nei secoli dei secoli.

Data una stringa di parole linguaggio, scrivi del codice che stampa True se tutte le parole hanno la stessa lunghezza, False altrimenti

Per avere un algoritmo efficiente, dovrai usare un while:

  • ferma il ciclo appena puoi determinare con certezza il risultato del programma

  • NON usare break

Mostra soluzione
[25]:


linguaggio = "armonia cosmica forever" # True #linguaggio = "guerra e violenza" # False #linguaggio = "vi rt uo so" # True #linguaggio = "sopraffazione inganno" # False #linguaggio = "nessuna armonia reale" # False #linguaggio = "pace" # True #linguaggio = "" # True # scrivi qui

Esercizio - lo sfrucugliatore

✪✪✪ Giustino il contadino ha deciso di dare una svolta high-tech alla sua azienda agricola, e ti chiede di sviluppare uno ‘sfrucugliatore’ di alberi (così lo chiama lui..) per percuotere gli alberi e raccogliere i frutti esotici che ha piantato in alta quota in montagna (ormai il cambiamento climatico lo permette…)

La piantagione è una sequenza di alberi da frutto, elementi del paesaggio (pietre, ghiaia, etc) e cartelli 'C'. L’inizio e la fine di una sottosequenza di alberi da frutto sono sempre marcate da un cartello.

Il veicolo da progettare dispone di un cassone di capienza 7 dove può mettere il raccolto.

Scrivi del codice che percorre la piantagione e raccoglie in cassone i frutti trovati

  • USA un while fermandolo non appena il cassone è pieno

  • NON usare breakcontinue

  • NON scrivere nomi dei frutti o elementi del paesaggio nel codice (niente 'banane' o 'sassi' ..). Puoi scrivere 'C'.

Esempio - data:

piantagione = ['pietre','sassi',  'C',   'banane',   'arance',  'manghi', 'C',    'sabbia', 'sassi', 'sassi',
                 'C',   'avocadi','C',   'gramigna','C',        'kiwi',  'manghi', 'C',     'C',     'C',
                 'rocce', 'C',    'lime', 'C',      'ciottoli', 'C',     'arance', 'cocco', 'C',     'ghiaia']

dopo il tuo codice, deve risultare:

>>> print(cassone)
['banane', 'arance', 'manghi', 'avocadi', 'kiwi', 'manghi', 'lime']
Mostra soluzione
[26]:
              #   0        1       2       3         4           5        6        7         8        9
piantagione = ['pietre','sassi',  'C',   'banane',   'arance',  'manghi', 'C',    'sabbia', 'sassi', 'sassi',
              #   10       11      12      13        14          15       16       17        18       19
                 'C',   'avocadi','C',   'gramigna','C',        'kiwi',  'manghi', 'C',     'C',     'C',
              #   20       21      22      23        24          25       26       27        28       29
                 'rocce', 'C',    'lime', 'C',      'ciottoli', 'C',     'arance', 'cocco', 'C',     'ghiaia']

#piantagione = ['C','C']   # []
#piantagione = ['C','limoni','C']   # ['limoni']
#piantagione = ['sabbia','C','limoni','C']   # ['limoni']
#piantagione = ['arance']   # []
#piantagione = ['C','1','2','3','4','5','6','7', '8','C']   # ['1','2','3','4','5','6','7']
#piantagione = ['C','1','2','C','x','C','3','4','5','6','7','8','C','9']   # ['1','2','3','4','5','6','7']


cassone = []

# scrivi qui


['banane', 'arance', 'manghi', 'avocadi', 'kiwi', 'manghi', 'lime']

Esercizio - la posta nella stiva

✪✪✪ Data una stringa e due caratteri car1 e car2, scrivi del codice che STAMPA True se tutte le occorrenze di car1 in stringa sono sempre seguite da car2.

Esempio - data:

stringa,car1,car2 = "accatastare la posta nella stiva", 's','t'

stampa True perchè tutte le occorrenze di s sono seguite da t

stringa,car1,car2 = "dadaista entusiasta", 's','t'

stampa False, perchè viene ritrovata la sequenza si dove s non è seguita da t

  • USA un while, cerca di farlo efficiente terminandolo appena puoi

  • NON usare break

Mostra soluzione
[27]:

stringa,car1,car2 = "accatastare la posta nella stiva", 's','t' # True #stringa,car1,car2 = "dadaista entusiasta", 's','t' # False #stringa,car1,car2 = "barbabietole", 't','o' # True #stringa,car1,car2 = "barbabietole", 'b','a' # False #stringa,car1,car2 = "a", 'a','b' # False #stringa,car1,car2 = "ab", 'a','b' # True #stringa,car1,car2 = "aa", 'a','b' # False # scrivi qui

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:

[28]:
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 !
[28]:
Python Tutor visualization

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.

[29]:
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!
[29]:
Python Tutor visualization

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
[30]:

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

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

[31]:

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
[32]:

lista = [] i = 0 # scrivi qui

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
[33]:

pila = ['S-Medioevo', 'V-Australia', 'V-Scozia', 'G-Sospetti', 'V-Caraibi'] viaggi = [] # scrivi qui

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
[34]:

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

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
[35]:

la = [3,5,6,7] # scrivi qui

Prosegui

Continua con le challenges