Sequenze e comprehensions

Scarica zip esercizi

Naviga file online

In Python è possibile scrivere codice elegante e compatto con le sequenze. Prima vedremo come scorrere le sequenze con gli iteratori e poi come costruirle con le comprehensions di liste, insiemi e dizionari.

Referimenti:

Che fare

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

sequences
    sequences.ipynb
    sequences-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 sequences.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

Iterabili - liste

Guardando i cicli abbiamo spesso parlato di iteratazione su sequenze, ma nel dettaglio, cosa vuol dire esattamente che una sequenza è iterabile ? In concreto, vuol dire che è possibile chiamare la funzione iter sulla sequenza.

Proviamo per esempio sulle familiari liste:

[2]:
iter(['a','b','c','d'])
[2]:
<list_iterator at 0x7efd24680b38>

Notiamo che Python ha creato un oggetto di tipo list_iterator.

NOTA: la lista non viene mostrata!

Puoi immaginare un iteratore come una specie di macchinetta ferma, che ogni volta che viene azionata produce un elemento di una sequenza, uno alla volta.

Tipicamente, un iteratore sa solo in quale posizione sta all’interno di una sequenza, e può fornirci gli elementi della sequenza uno per uno se li chiediamo ripetutamente con la funzione next:

[3]:
iteratore = iter(['a','b','c','d'])
[4]:
next(iteratore)
[4]:
'a'
[5]:
next(iteratore)
[5]:
'b'
[6]:
next(iteratore)
[6]:
'c'
[7]:
next(iteratore)
[7]:
'd'

Nota come l’iteratore abbia uno stato per tenere traccia di dove siamo nella sequenza (in inglese diremmo che è stateful). Lo stato viene cambiato ad ogni chiamata della funzione next.

Se proviamo a chiedere più elementi di quanti ve ne sono disponibili, Python solleva un’eccezione StopIteration:

next(iteratore)

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-65-4518bd5da67f> in <module>()
----> 1 next(iteratore)

StopIteration:

iterabili - range

Abbiamo provato ad iterare su una lista, che è una sequenza completamente materializzata in memoria su cui scorriamo con l’oggetto iteratore. Esistono anche sequenze particolari che non sono materializzate in memoria, come per esempio range.

Precedentemente abbiamo usato range nei cicli for for ottenere una sequenza di numeri, ma esattamente, che cosa fa la funzione range? Proviamo a chiamarla da sola:

[8]:
range(4)
[8]:
range(0, 4)

Forse ci attendevamo una sequenza di numeri, invece Python ci mostra un oggetto di tipo range (indicando anche l’estremo inferiore del range).

NOTA: Al momento in memoria non è presente nessuna sequenza di numeri

Abbiamo solo un oggetto iterabile ‘fermo’ che se vogliamo può fornirci i numeri

Come possiamo chiederglieli?

Abbiamo già visto che si può usare un for:

[9]:
for x in range(4):
    print(x)
0
1
2
3

In alternativa, possiamo passare range alla funzione iter che produce un iteratore.

ATTENZIONE: range è iterabile ma NON è un iteratore !!

Per ottenere l’iteratore dobbiamo chiamare la funzione iter sull’oggetto range

[10]:
iteratore = iter(range(4))

Anche iter produce un oggetto ‘fermo’, che non ha ancora materializzato in memoria dei numeri:

[11]:
iteratore
[11]:
<range_iterator at 0x7efd245e7db0>

Per chiederglieli dobbiamo usare la funzione next:

[12]:
next(iteratore)
[12]:
0
[13]:
next(iteratore)
[13]:
1
[14]:
next(iteratore)
[14]:
2
[15]:
next(iteratore)
[15]:
3

Nota come l’iteratore abbia uno stato, che viene cambiato ad ogni chiamata di next per tenere traccia di dove siamo nella sequenza.

Se proviamo a chiedere più elementi di quanti ve ne sono disponibili, Python solleva un’eccezione StopIteration:

next(iteratore)

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-65-4518bd5da67f> in <module>()
----> 1 next(iteratore)

StopIteration:

Materializzare una sequenza

Abbiamo detto che un oggetto range non materializza fisicamente in memoria tutti i numeri contemporaneamente. Solo ottenendo l’iteratore, li materializziamo uno per uno. E volessimo una lista con tutti i numeri ? Nel foglio sulle liste abbiamo visto che passando alla funzione list una sequenza, viene creata una nuova lista che contiene tutti gli elementi della sequenza. Abbiamo parlato genericamente di sequenza, ma il termine più corretto sarebbe stato iterabile.

Se passiamo a list un qualunque oggetto iterabile allora verrà costruita la lista - come abbiamo visto range è iterabile quindi proviamo:

[16]:
list(range(4))
[16]:
[0, 1, 2, 3]

Voilà ! Adesso la sequenza è tutta fisicamente presente in memoria.

ATTENZIONE: list consuma l’iteratore!

Se provi a chiamare due volte list sullo stesso iteratore, otterrai una lista vuota:

[17]:

sequenza = range(4)
iteratore = iter(sequenza)
[18]:
nuova1 = list(iteratore)
[19]:
nuova1
[19]:
[0, 1, 2, 3]
[20]:
nuova2 = list(iteratore)
[21]:
nuova2
[21]:
[]

E se volessimo accedere direttamente ad una posizione specifica della sequenza generata dall’iteratore? Proviamo ad estrarre direttamente la lettera ad indice 2 qui:

[22]:
sequenza = range(4)
iteratore = iter(sequenza)
iteratore[2]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-129-3c080cc9e700> in <module>()
      1 sequenza = range(4)
      2 iteratore = iter(sequenza)
----> 3 iteratore[3]

TypeError: 'range_iterator' object is not subscriptable

… purtroppo ci becchiamo un errore.

Non ci restano che due alternative:

  1. prima convertiamo a lista e poi usiamo le quadre

  2. chiamiamo 4 volte next (ricordati che gli indici partono da zero)

L’opzione a) spesso sembra comoda, ma fai attenzione: convertire a lista un’iteratore crea una NUOVA lista in memoria, se la lista di partenza è molto grande e/o si fa questa operazione molte volte si rischia di occupare memoria per niente.

Rivediamo l’esempio in Python Tutor:

[23]:
# 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
[24]:
sequenza = range(4)
iteratore = iter(sequenza)
nuova1 = list(iteratore)
nuova2 = list(iteratore)

jupman.pytut()
[24]:

DOMANDA: Occupa più memoria l’oggetto a o l’oggetto b ?

a = range(10)
b = range(10000000)
Mostra risposta

DOMANDA: Occupa più memoria l’oggetto a o l’oggetto b ?

a = list(range(10))
b = list(range(10000000))
Mostra risposta

Domande range

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

  1. range(3)
    
  2. range()
    
  3. list(range(-3))
    
  4. range(3,6)
    
  5. list(range(5,4))
    
  6. list(range(3,3))
    
  7. range(3) + range(6)
    
  8. list(range(3)) + list(range(6))
    
  9. list(range(0,6,2))
    
  10. list(range(9,6,-1))
    

reversed

reversed è una funzione che prende come parametro una sequenza e PRODUCE un NUOVO iteratore che consente di scorrere la sequenza in ordine inverso.

ATTENZIONE: chiamando reversed si ottiene direttamente un iteratore !

Quindi non serve fare ulteriori chiamate a iter come fatto per range!

Vediamo meglio cosa vuol dire con un esempio:

[25]:
la = ['p','r','o','v','a']
[26]:
reversed(la)
[26]:
<list_reverseiterator at 0x7efd244a7a58>

Vediamo che reversed ha prodotto un risultato che è un iteratore (non una lista rovesciata).

INFO: gli iteratori occupano poca memoria

Creare un iteratore da una sequenza crea solo una specie di puntatore, non crea nuove regioni di memoria.

Inoltre, vediamo che la lista originale associata a la non è cambiata:

[27]:
print(la)
['p', 'r', 'o', 'v', 'a']

ATTENZIONE: la funzione reversed è diversa dal metodo reverse

Nota la d finale! Se provassiamo a chiamarla come un metodo otterremmo un errore:

>>> la.reversed()

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-182-c8d1eec57fdd> in <module>
----> 1 la.reversed()

AttributeError: 'list' object has no attribute 'reversed'

iterare con next

Come facciamo ad ottenere in memoria una lista rovesciata? In altre parole, come facciamo ad azionare la macchinetta iteratore?

Possiamo chiedere all’iteratore un elemento alla volta con la funzione next:

[28]:
la = ['a','b','c']
[29]:
iteratore = reversed(la)
[30]:
next(iteratore)
[30]:
'c'
[31]:
next(iteratore)
[31]:
'b'
[32]:
next(iteratore)
[32]:
'a'

Una volta esaurito l’iteratore, chiamando ancora next otterremo un errore:

next(iteratore)

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-248-4518bd5da67f> in <module>
----> 1 next(iteratore)

StopIteration:

Proviamo a crearci manualmente una lista di destinazione lb e aggiungere gli elementi che otteniamo mano a mano:

[33]:
la = ['a','b','c']
iteratore = reversed(la)
lb = []
lb.append(next(iteratore))
lb.append(next(iteratore))
lb.append(next(iteratore))
print(lb)

jupman.pytut()
['c', 'b', 'a']
[33]:

Esercizio - sconcerto

Scrivi del codice che data una lista di caratteri la, mette in una lista lb tutti i caratteri in posizione dispari presi della lista la rovesciata

  • usa reversed e next

  • NON modificare la

  • NON usare indici negativi

  • NON usare list

Esempio - data

#      8    7    6    5    4    3    2    1    0
la = ['s', 'c', 'o', 'n', 'c', 'e', 'r', 't', 'o']
lb = []

Dopo il tuo codice deve mostrare

>>> print(lb)
['t', 'e', 'n', 'c']
>>> print(la)
['s', 'c', 'o', 'n', 'c', 'e', 'r', 't', 'o']

Ti invitiamo a risolvere il problema in diversi modi:

MODO 1 - senza ciclo: Supponi che la lunghezza della lista sia fissa, e chiama ripetutamente next senza usare un ciclo

MODO 2 - while: Supponi di avere una lista di lunghezza arbitraria, e prova a generalizzare il precedente codice usando un ciclo while al cui interno chiamerai next

  • SUGGERIMENTO 1: tieni traccia della posizione a cui sei con un contatore i

  • SUGGERIMENTO 2: non si può chiamare len su un iteratore, quindi nella condizione del while dovrai usare la lunghezza della lista originale

MODO 3 - for: questo è il modo più elegante. Supponi di avere una lista di lunghezza arbitraria e usa un ciclo for x in reversed(la)

  • SUGGERIMENTO: dovrai comunque tener traccia della posizione a cui sei con un contatore i

Mostra soluzione
[34]:
# MODO 1 MANUALE

#      8    7    6    5    4    3    2    1    0
la = ['s', 'c', 'o', 'n', 'c', 'e', 'r', 't', 'o']
lb = []

# scrivi qui


['t', 'e', 'n', 'c']
Mostra soluzione
[35]:
# MODO 2 CON IL WHILE

#      8    7    6    5    4    3    2    1    0
la = ['s', 'c', 'o', 'n', 'c', 'e', 'r', 't', 'o']
lb = []

# scrivi qui


['t', 'e', 'n', 'c']
Mostra soluzione
[36]:
# MODO 3: for

#      8    7    6    5    4    3    2    1    0
la = ['s', 'c', 'o', 'n', 'c', 'e', 'r', 't', 'o']
lb = []

# scrivi qui


['t', 'e', 'n', 'c']

Materializzare un iteratore

Per fortuna per ottenere subito una lista dall’iteratore c’è un modo meno laborioso.

Abbiamo visto che quando vogliamo creare una nuova lista a partire da una sequenza, possiamo usare list come se fosse una funzione. Possiamo farlo anche in questo caso, interpretando l’iteratore come se fosse una sequenza:

[37]:
la = ['p', 'r', 'o', 'v', 'a']
list( reversed(la) )
[37]:
['a', 'v', 'o', 'r', 'p']

Nota bene abbiamo generato una NUOVA lista, quella originale associata ad la è sempre la stessa:

[38]:
la
[38]:
['p', 'r', 'o', 'v', 'a']

Vediamo meglio cosa è successo usando Python Tutor (per evidenziare i passaggi abbiamo creato delle variabili extra):

[39]:
la = ['p','r','o','v','a']
iteratore = reversed(la)
nuova = list(iteratore)
print("la è",la)
print("nuova è",nuova)

jupman.pytut()
la è ['p', 'r', 'o', 'v', 'a']
nuova è ['a', 'v', 'o', 'r', 'p']
[39]:

DOMANDA Il seguente codice, che effetto produce?

la = ['p','o','n','t','e']
lb = list(reversed(reversed(la)))

sorted

La funzione sorted prende una sequenza come parametro ritorna una NUOVA lista ordinata

ATTENZIONE: sorted ritorna una LISTA, non un iteratore !

[40]:
sorted(['g','a','e','d','b'])
[40]:
['a', 'b', 'd', 'e', 'g']

ATTENZIONE: sorted è una funzione diversa dal metodo sort !

Nota la ed finale! Se provassiamo a chiamarla come un metodo otterremmo un errore:

>>> la.sorted()

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-182-c8d1eec57fdd> in <module>
----> 1 la.reversed()

AttributeError: 'list' object has no attribute 'sorted'

Esercizio - reversort

✪ Data una una lista di nomi, produrre una lista ordinata in ordine inverso

Ci sono almeno due modi per farlo in una sola linea di codice, trovarli entrambi

  • INPUT: ['Maria','Paolo','Giovanni','Alessia','Greta']

  • OUTPUT: ['Paolo', 'Maria', 'Greta', 'Giovanni', 'Alessia']

Mostra soluzione
[41]:
# scrivi qui


[41]:
['Paolo', 'Maria', 'Greta', 'Giovanni', 'Alessia']

zip

Supponiamo di avere due liste quadri e anni, con rispettivamente nomi di quadri famosi e le date in cui sono stati dipinti:

[42]:
quadri = ["La Gioconda", "La Nascita di Venere", "I Girasoli"]
anni = [1503, 1482, 1888]

Vogliamo produrre una lista nuova che contenga delle tuple che associano a ciascun quadro l’anno in cui è stato dipinto:

[('La Gioconda', 1503),
 ('La Nascita di Venere', 1482),
 ('I Girasoli', 1888)]

Per farlo vi sono vari modi ma senz’altro il più elegante è con la funzione zip che produce un iteratore:

[43]:
zip(quadri, anni)
[43]:
<zip at 0x7efd244ac808>

Per quanto non si veda scritto ‘iteratore’ nel nome dell’oggetto, possiamo comunque usarlo come tale con next:

[44]:
iteratore = zip(quadri, anni)
next(iteratore)
[44]:
('La Gioconda', 1503)
[45]:
next(iteratore)
[45]:
('La Nascita di Venere', 1482)
[46]:
next(iteratore)
[46]:
('I Girasoli', 1888)

E come fatto in precedenza, possiamo convertire tutto a lista con list:

[47]:
quadri = ["La Gioconda", "La Nascita di Venere", "I Girasoli"]
anni = [1503, 1482, 1888]

list(zip(quadri,anni))
[47]:
[('La Gioconda', 1503), ('La Nascita di Venere', 1482), ('I Girasoli', 1888)]

Se le liste sono di lunghezza differente, la sequenza prodotta da zip sarà lunga come la sequenza di input più corta:

[48]:
list(zip([1,2,3], ['a','b','c','d','e']))
[48]:
[(1, 'a'), (2, 'b'), (3, 'c')]

Volendo, si può passare un numero arbitrario di sequenze - per esempio passandone tre otteremo delle triple di valori:

[49]:
canzoni = ['Imagine', 'Hey Jude', 'Satisfaction', 'Yesterday' ]
autori = ['John Lennon','The Beatles', 'The Rolling Stones', 'The Beatles']
anni = [1971, 1968, 1965, 1965]
list(zip(canzoni, autori, anni))
[49]:
[('Imagine', 'John Lennon', 1971),
 ('Hey Jude', 'The Beatles', 1968),
 ('Satisfaction', 'The Rolling Stones', 1965),
 ('Yesterday', 'The Beatles', 1965)]

Esercizio - scala

Data una numero n, creare una lista di tuple che per ogni numero intero \(x\) tale che \(0 \leq x \leq n\) associa il numero \(n - x\)

  • INPUT: n=5

  • OUTPUT: [(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)]

Mostra soluzione
[50]:
n = 5
# scrivi qui


[50]:
[(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)]

List comprehensions

Riferimenti: Pensare in Python - Capitolo 19.2

Le list comprehensions servono per generare una NUOVA lista eseguendo la stessa operazione su tutti gli elementi di una sequenza di partenza. Come sintassi imitano le liste, infatti iniziano e finiscono con le parentesi quadre [ ], ma dentro contengono un for speciale per ciclare dentro un sequenza :

[51]:
numeri = [2,5,3,4]

raddoppiati = [x*2 for x in numeri]

raddoppiati
[51]:
[4, 10, 6, 8]

Nota che la variabile numeri è ancora associata alla lista originale:

[52]:
numeri
[52]:
[2, 5, 3, 4]

Cosa è successo ? Abbiamo indicato a Python un nome di variabile x che ci siamo inventati noi, e gli abbiamo detto di scorrere la lista numeri: ad ogni iterazione, la variabile x viene associata ad un diverso valore della lista numeri. Tale valore lo possiamo riusare nell’espressione che indichiamo a sinistra del for, che in questo caso è x*2.

Come nome per la variabile abbiamo usato x, ma potremmo usare un qualunque altro nome, per esempio questo codice è equivalente al precedente:

[53]:
numeri = [2,5,3,4]

raddoppiati = [numero * 2 for numero in numeri]

raddoppiati
[53]:
[4, 10, 6, 8]

Nella parte a sinistra del for possiamo scrivere qualunque espressione che produca un valore, per esempio qua scriviamo x + 1 per incrementare tutti i numeri della lista originale.

[54]:
numeri = [2,5,3,4]

aumentati = [x + 1 for x in numeri]

aumentati
[54]:
[3, 6, 4, 5]

DOMANDA: Questo codice cosa produrrà? Se lo visualizziamo in Python Tutor, la ed lb punteranno ad oggetti diversi?

la = [7,5,6,9]
lb = [x for x in la]
Mostra risposta
[55]:
la = [7,5,6,9]
lb = [x for x in la]

jupman.pytut()
[55]:

list comprehension su stringhe

DOMANDA: Questo codice cosa produrrà?

[x for x in 'domanda']
Mostra risposta

Adesso supponiamo di avere una lista di animali e vogliamo produrne un’altra con gli stessi nomi ma in maiuscolo. Possiamo farlo in modo compatto con una list comprehension così:

[56]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = [animale.upper() for animale in animali]
[57]:
nuova_lista
[57]:
['CANI', 'GATTI', 'SCOIATTOLI', 'ALCI']

Nella parte a sinistra riservata all’espressione abbiamo usato sulla variabile stringa animale il metodo .upper(). Sappiamo che le stringhe sono immutabili, quindi siamo sicuri che la chiamata al metodo produce una NUOVA stringa. Vediamo cosa è successo in Python Tutor:

[58]:

animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = [animale.upper() for animale in animali]

jupman.pytut()

[58]:

✪ ESERCIZIO: Prova qua sotto ad usare una list comprehension per mettere tutti i caratteri in minuscolo (metodo .lower())

Mostra soluzione
[59]:
animali = ['caNI', 'gaTTi', 'SCOIATtoli', 'aLLci']

# scrivi qui


[59]:
['cani', 'gatti', 'scoiattoli', 'allci']

Domande list comprehension

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

  1. [x for [4,2,5]]
    
  2. x for x in range(3)
    
  3. [x for y in 'cartoccio']
    
  4. [for x in 'zappa']
    
  5. [for [3,4,5]]
    
  6. [k + 1 for k in 'bozza']
    
  7. [k + 1 for k in range(5)]
    
  8. [k > 3 for k in range(7)]
    
  9. [s + s for s in ['lam','pa','da']]
    
  10. la = ['x','z','z']
    [x for x in la] + [y for y in la]
    
  11. [x.split('-') for x in ['a-b', 'c-d', 'e-f']]
    
  12. ['@'.join(x) for x in [['a','b.com'],['c','d.org'],['e','f.net'] ]]
    
  13. ['z' for y in 'borgo'].count('z') == len('borgo')
    
  14. m = [['a','b'],['c','d'],['e','f'] ]
    la = [x.pop() for x in m]   # sconsigliabile - perchè ?
    print(' m:', m)
    print('la:',la)
    

Esercizio - list comprehension

Esercizio - potenza

✪ Data una lista di numeri, produrre una lista con la potenza quadrata dei numeri di input

  • INPUT: [4,5,9]

  • OUTPUT: [16, 25, 81]

Mostra soluzione
[60]:
import math

# scrivi qui


[60]:
[16, 25, 81]

Esercizio - radice

✪ Data una lista di numeri, produrre una lista con la radice quadrata dei numeri di input

  • INPUT: [16,25,81]

  • OUTPUT: [4.0, 5.0, 9.0]

Mostra soluzione
[61]:
import math

# scrivi qui


[61]:
[4.0, 5.0, 9.0]

Esercizio - primi car

✪ Data una lista di stringhe, produrre una lista con i primi caratteri di ogni stringa

  • INPUT: ['Quando', 'Fuori', 'Piove', 'Programmiamo']

  • OUTPUT: ['Q','F','P','P']

Mostra soluzione
[62]:
# scrivi qui


[62]:
['Q', 'F', 'P', 'P']

Esercizio - porta pazienza

✪ Da una lista di stringhe, produrre una lista con le lunghezze di tutte le liste

  • INPUT: ['non', 'ti', 'preoccupare', 'e', 'porta', 'pazienza']

  • OUTPUT: [3,2,11,1,5,8]

Mostra soluzione
[63]:
# scrivi qui


[63]:
[3, 2, 11, 1, 5, 8]

Esercizio - maggiore 3

✪ Data una lista di numeri, produrre una lista con True se il corrispondente elemento è maggiore di 3, False altrimenti

  • INPUT: [4,1,0,5,0,9,1]

  • OUTPUT: [True, False, False, True, False, True, False]

Mostra soluzione
[64]:
# scrivi qui


[64]:
[True, False, False, True, False, True, False]

Esercizio - pari

✪ Data una lista di numeri, produrre una lista con True se il corrispondente elemento è pari

  • INPUT: [3,2,4,1,5,3,2,9]

  • OUTPUT: [False, True, True, False, False, False, True, False]

Mostra soluzione
[65]:
# scrivi qui


[65]:
[False, True, True, False, False, False, True, False]

Esercizio - capi

✪ Data una lista di stringhe di almeno due caratteri, produrre una lista di stringhe con i primi e ultimi caratteri

  • INPUT: ['parto', 'per', 'il', 'fronte']

  • OUTPUT: ['po', 'pr', 'il', 'fe']

Mostra soluzione
[66]:
# scrivi qui


[66]:
['po', 'pr', 'il', 'fe']

Esercizio - trattini

✪ Data una lista di liste di caratteri, produrre una lista di stringhe con caratteri separati da trattini

  • INPUT: [['a','b'],['c','d','e'], ['f','g']]

  • OUTPUT: ['a-b', 'c-d-e', 'f-g']

Mostra soluzione
[67]:
# scrivi qui


[67]:
['a-b', 'c-d-e', 'f-g']

Esercizio - lollosa

✪ Data una stringa s, produrre una lista di tuple avente per ogni carattere il numero di occorrenze del carattere nella stringa.

  • INPUT: s = 'lollosa'

  • OUTPUT: [('l', 3), ('o', 2), ('l', 3), ('l', 3), ('o', 2), ('s', 1), ('a', 1)]

Mostra soluzione
[68]:
s = 'lollosa'
# scrivi qui


[68]:
[('l', 3), ('o', 2), ('l', 3), ('l', 3), ('o', 2), ('s', 1), ('a', 1)]

Esercizio - cane gatto

✪ Data una lista di stringhe, produrre una lista con le stringhe senza caratteri iniziale e finale

  • INPUT: ['bue','gatto','cane', 'mucca' ]

  • OUTPUT: ['u', 'att', 'an', 'ucc']

Mostra soluzione
[69]:
# scrivi qui


[69]:
['u', 'att', 'an', 'ucc']

Esercizio - puffi

✪ Dati dei nomi produrre una lista con i nomi in ordine alfabetico tutti in maiuscolo

  • INPUT: ['Quattrocchi', 'Forzuto', 'Puffetta', 'Tontolone']

  • OUTPUT: ['FORZUTO', 'PUFFETTA', 'QUATTROCCHI', 'TONTOLONE']

Mostra soluzione
[70]:
# scrivi qui


[70]:
['FORZUTO', 'PUFFETTA', 'QUATTROCCHI', 'TONTOLONE']

Esercizio - metalli preziosi

✪ Date due liste valori e metalli produrre una lista contenente tutte le coppie valore metallo come tuple

INPUT:

valori = [10,25,50]
metalli = ['argento','oro','platino']

OUTPUT: [(10, 'argento'), (25, 'oro'), (50, 'platino')]

Mostra soluzione
[71]:
valori = [10,25,50]
metalli = ['argento','oro','platino']

# scrivi qui


[71]:
[(10, 'argento'), (25, 'oro'), (50, 'platino')]

List comprehension filtrate

Durante la costruzione di una list comprehension è possibile filtrare gli elementi presi dalla sequenza che si sta esaminando utilizzando un if. Per esempio, l’espressione seguente considera dalla sequenza di numeri solo i numeri maggiori di cinque:

[72]:
[x for x in [7,4,8,2,9] if x > 5]
[72]:
[7, 8, 9]

Dopo l’if possiamo mettere qualunque espressione che riusi la variabile su cui stiamo iterando, per esempio se stiamo iterando su una stringa possiamo trattenere solo i caratteri maiuscoli:

[73]:
[x for x in 'Il Mondo Gira' if x.isupper()]
[73]:
['I', 'M', 'G']

ATTENZIONE: gli else non sono supportati

Per esempio, scrivere questo genera un errore:

[x for x in [7,4,8,2,9] if x > 5 else x + 1]   # SBAGLIATO!

File "<ipython-input-74-9ba5c135c58c>", line 1
    [x for x in [7,4,8,2,9] if x > 5 else x + 1]
                                        ^
SyntaxError: invalid syntax

Domande list comprehension filtrate

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

  1. [x for x in range(100) if False]
    
  2. [x for x in range(3) if True]
    
  3. [x for x in range(6) if x > 3 else 55]
    
  4. [x for x in range(6) if x % 2 == 0]
    
  5. [x for x in {'a','b','c'}]  # occhio all'ordine
    
  6. [x for x in [[5], [2,3], [4,2,3], [4]] if len(x) > 2]
    
  7. [(x,x) for x in 'xyxyxxy' if x != 'x' ]
    
  8. [x for x in ['abCdEFg'] if x.upper() == x]
    
  9. la = [1,2,3,4,5]
    [x for x in la if x > la[len(la)//2]]
    

Esercizio - list comprehension filtrate

Esercizio - savana

Data una lista di stringhe, produrre una lista con solo le stringhe di lunghezza maggiore di 6

  • INPUT: ['zebra', 'leopardo', 'giraffa', 'gnu', 'rinoceronte', 'leone']

  • OUTPUT: ['leopardo', 'giraffa', 'rinoceronte']

Mostra soluzione
[74]:
# scrivi qui


[74]:
['leopardo', 'giraffa', 'rinoceronte']

Esercizio - barZa

Data una lista di stringhe, produrre una lista con solo le stringhe che contengono almeno una 'z'. Le stringhe selezionate vanno trasformate in modo da mettere la Z in maiuscolo.

  • INPUT: ['barza', 'palco','porzione', 'corsa', 'maschera', 'zona']

  • OUTPUT: ['barZa', 'porZione', 'Zona']

[75]:
[x.replace('z','Z') for x in ['barza', 'palco','porzione', 'corsa', 'maschera', 'zona'] if 'z' in  x]
[75]:
['barZa', 'porZione', 'Zona']
[ ]: