Cicli while 1 - introduzione
Scarica zip esercizi
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
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.
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
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]:
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:
inizializzare una variabile all’esterno del ciclo
una condizione dopo la scritta
while
che valuta quella variabile (e opzionalmente altro)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 rispostaDomande
DOMANDA: Guarda i seguenti frammenti di codice, e per ciascuno cerca di indovinare quale risultato produce (o se da errore):
i = 0 while i < 3: print(i)
k = 0 while k < 5: print(k) k + 1
i = 0 while i < 3: print(i) i += 1
i = 0 while False: print(i) i += 1 print('Finito !')
i = 0 while i < 3: print(i) i += 1
k = 0 while k < 2 print(i) k += 1
i = 0 while i < 3: print('GAM') i = i + 1
while zanza < 2 print('ZANZA') zanza += 1
i = 0 while False: print(i) i = i + 1 print('DARK')
i = 0 while True: print(i) i = i + 1 print('LIGHT')
while 2 + 3: print('z') print('')
i = 10 while i > 0: if i > 5: print(i) i -= 1 print('WAM')
i = 10 while i > 0: if i > 5: print(i) i -= 1 print('MAW')
import random x = 0 while x < 7: x = random.randint(1,10) print(x) print('LUCK')
x,y = 0,0 while x + y < 4: x += 1 y += 1 print(x,y)
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
[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
[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]:
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):
i = 1 while i < 4: print('Ho contato fino a', i) i += 1 continue print('Ciclo finito !')
i = 1 while i < 4: print('Ho contato fino a', i) continue i += 1 print('Ciclo finito !')
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 !')
i = 0 while True: i += 1 print(i) if i > 3: break print('BONG')
i = 0 while True: if i < 3: continue else: break i += 1 print('ZONG')
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
[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
[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)
[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
[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
[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
[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 dix
, 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
[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?
Per costruire la nostra ricerca, ci serviranno:
variabile di controllo
condizione di termine
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:
il modo più diretto di fare un controllo di uscita è dentro il corpo stesso del
while
, mettendo unif
che al verificarsi del ritrovamento provoca l’esecuzione di unbreak
. Non è affatto elegante, ma può essere un primo approccio.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 ricercaRICORDATI 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
[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 break
nè continue
: per verificare il ritrovamento, dovrai arricchire la condizione di terminazione.
[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?
SUGGERIMENTO: Se hai dubbi prova a guardare il capitolo booleani - ordine di valutazione
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()
[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
daSanta Fe
fino aTombstone
che rappresentiamo come lista di stringheper rappresentare dove sono i banditi nella strada, usiamo due indici
butch
ecarson
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 inizialecarson
ebutch
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 !
[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
[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 è pienoNON usare
break
nècontinue
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']
[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 puoiNON usare break
[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]:
Guardando il codice, possiamo notare che:
la variabile
mazzo
viene inizializzatasi verifica che la dimensione di
mazzo
sia maggiore di zeroad ogni passo la lista
mazzo
viene MODIFICATA riducendone la dimensioneritorna 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:
troviamo cuori, e interrompiamo la ricerca
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]:
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
[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):
while []: print('z') print('BIG')
while ['a']: print('z') print('BUG')
la = [] while len(la) < 3: la.append('x') print(la)
la = ['x','y','z'] while len(la) > 0: print(la.pop())
la = ['x','y','z'] while la: print(la.pop(0))
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]
[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
[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: []
[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. attacca14
)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 è []
[35]:
la = [3,5,6,7]
# scrivi qui
Prosegui
Continua con le challenges