<jupyter_start><jupyter_text>Liste 2 - operatori  [Scarica zip esercizi](../_static/generated/lists.zip)[Naviga file online](https://github.com/DavidLeoni/softpython-it/tree/master/lists)Per manipolare le liste vi sono diversi operatori. I seguenti si comportano come quelli visti per le stringhe.|Operatore|Risultato|Significato||---|---|----||`len`(lst)|`int`|Ritorna la lunghezza di una lista||list`[`int`]`|obj|Legge/scrive un elemento all'indice specificato||list`[`int`:`int`]`|`list`| Estrae una sotto-lista - ritorna una NUOVA lista||obj `in` list|`bool`|Controlla se un elemento è presente in una lista||list `+` list|`list`|Concatena due liste - ritorna una NUOVA lista||`max`(lst)|`int`|Data una lista di numeri, ritorna il massimo||`min`(lst)|`int`|Data una lista di numeri, ritorna il minimo||`sum`(lst)|`int`|Data una lista di numeri, li somma tutti||list `*` int|`list`| Replica la lista - ritorna una NUOVA lista||`==`,`!=`|`bool`| Controlla se due liste sono uguali o differenti|  Che fare- scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere: ```lists    lists1.ipynb    lists1-sol.ipynb             lists2.ipynb    lists2-sol.ipynb             lists3.ipynb    lists3-sol.ipynb             lists4.ipynb    lists4-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 `lists2.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`  Lunghezza di una listaUna lista è una sequenza, e come per tutte le sequenze per ottenere la lunghezza si può usare la funzione `len`:<jupyter_code>a = [7,5,8]
len(a)
b = [8,3,6,4,7]
len(b)<jupyter_output><empty_output><jupyter_text>Se una lista contiene altre liste, contano come singoli elementi:<jupyter_code>mista = [ 
            [4,5,1],
            [8,6],
            [7,6,0,8],
        ]
len(mista)<jupyter_output><empty_output><jupyter_text>**ATTENZIONE: NON puoi usare `len` come se fosse un metodo**Per es questo NON funziona: `[3,4,2].len()` **ESERCIZIO**: Prova a scrivere `[3,4,2].len()` qua sotto, che errore appare?<jupyter_code># scrivi qui

#[3,4,2].len()<jupyter_output><empty_output><jupyter_text>**ESERCIZIO**: Prova a scrivere `[3,4,2].len` SENZA le doppie tonde alla fine, che errore appare?<jupyter_code># scrivi qui

#[3,4,2].len<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Se `x` è una lista qualunque, scrivendo`len(len(x))`cosa otteniamo?1. la lunghezza della lista2. un errore3. qualcos'altro **RISPOSTA**: la 2: `len` vuole come argomento _una sequenza_ e restituisce _un numero_, quindi la chiamata interna a `len(x)` produce un numero che viene dato al `len` esterno e a quel punto Python si lamenterà che ha ricevuto un numero invece di una sequenza. Prova a verificare che errore appare scrivendo `len(len(x))` qua sotto **DOMANDA**: Guarda questa espressione, senza eseguirla. Cosa produce? ```python[len([]), len([len(['a','b'])])]```1. un errore (quale?)2. un numero (quale?)3. una lista (quale?)Prova a scrivere a mano il risultato, e poi confrontalo con quello ottenuto eseguendo il codice in una cella. **RISPOSTA**: La 3: la lista `[0, 1]` **DOMANDA**: Guarda questa espressione, senza eseguirla. Cosa produce? ```pythonlen([[[],[]],[],[[[]]],[[],[]]])```1. un errore (quale?)2. un numero (quale?)3. una lista (quale?) **RISPOSTA**: la 2. produce il numero 4 **DOMANDA**: Cosa produce la seguente espressione?```python[[((len('ababb')))],len(["argg",('b'),("c")]), len([len("bc")])]``` **RISPOSTA**: `[[5], 3, 1]`  Leggere un elementoCome per le stringhe, possiamo accedere ad un elemento di una lista mettendo l'indice della posizione a cui vogliamo accedere tra parentesi quadre:<jupyter_code># 0   1   2   3   
la = [70, 60, 90, 50]<jupyter_output><empty_output><jupyter_text>**Come per tutte le sequenze, le posizioni iniziano da `0`:**<jupyter_code>la[0]
la[1]
la[2]
la[3]<jupyter_output><empty_output><jupyter_text>Come per le stringhe, se sforiamo con l'indice otteniamo un errore: ```pythonla[4]---------------------------------------------------------------------------IndexError                                Traceback (most recent call last) in ----> 1 la[4]IndexError: list index out of range``` Di nuovo come per le stringhe possiamo ottenere l'ultimo elemento usando un indice negativo:<jupyter_code># 0   1   2   3   
la = [70, 60, 90, 50]
la[-1]
la[-2]
la[-3]
la[-4]<jupyter_output><empty_output><jupyter_text>Se esageriamo ed andiamo oltre la lunghezza della lista, otteniamo un errore: ```pythonla[-5]---------------------------------------------------------------------------IndexError                                Traceback (most recent call last) in ----> 1 la[-5]IndexError: list index out of range``` **DOMANDA**: se `x` è una lista qualunque, scrivendo ```pythonx[0]```cosa otteniamo?1. il primo elemento della lista2. sempre un errore3. a volte un elemento a volte un errore a seconda della lista **RISPOSTA**:  la 3: se la lista è vuota Python non troverà l'elemento e ci darà un errore. Quale? Prova a scrivere nella cella sotto `[][0]` e vedi cosa succede. **DOMANDA**: se `x` è una lista qualunque, scrivendo```pythonx[len(x)]```cosa otteniamo?1. un elemento della lista2. sempre un errore3. a volte un elemento a volte un errore a seconda della lista  Esercizio - L'apprendista di GutenbergQuale onore! Alla tua età assunta come apprendista del maestro Gutenberg!La tua mansione è quella di comporre le pagine con i blocchetti di caratteri in ferro in modo che gli altri collaboratori poi mandino il tutto alla pressa da stampa.Hai a disposizione una lista in cui sono salvati i blocchetti originali. Riesci a stampare la scritta `Gutenberg` ?* **NON** scrivere caratteri o stringhe aggiuntive (es: niente `'g'`o `'G'`!)* ogni lettera **PUO'** essere riutilizzata<jupyter_code>#jupman-purge-output
lettere = ['b', 'e', 'g', 'n', 'r', 't', 'u']   # Gutenberg
#lettere = ['a', 'm', 's', 'p', 'o', 'a', 't']  # Stampamos
    
l = lettere      # Creiamo una nuova variabile più corta per comodità

# scrivi qui
# SOLUZIONE 1: non propriamente ottimale
print(l[2].upper(), l[6], l[5], l[1], l[3], l[0], l[1],  l[4], l[2])
# SOLUZIONE 2
print(f"{l[2].upper()}{l[6]}{l[5]}{l[1]}{l[3]}{l[0]}{l[1]}{l[4]}{l[2]}")
# SOLUZIONE 3
print("%s%s%s%s%s%s%s%s%s" % (l[2].upper(), l[6], l[5], l[1], l[3], l[0], l[1], l[4], l[2]))<jupyter_output>G u t e n b e r g
Gutenberg
Gutenberg<jupyter_text>**RISPOSTA**: La 2. sempre un errore: `len(x)` sarà sempre un numero uguale all'ultimo indice disponibile della lista + 1  Scrivere un elementoVisto che le liste sono MUTABILI, dato un oggetto lista possiamo cambiare il contenuto di una qualunque cella al suo interno.Supponiamo per esempio di voler cambiare la cella all'indice `2` della lista `la`, cambiandolo da `6` a `5`:<jupyter_code>#0  1  2  3   
la = [7, 9, 6, 8]<jupyter_output><empty_output><jupyter_text>Possiamo scrivere così:<jupyter_code>la[2] = 5

la<jupyter_output><empty_output><jupyter_text>Guardiamo meglio che succede in Python Tutor:<jupyter_code># 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 sys
sys.path.append('../')
import jupman
#     0  1  2  3   
la = [7, 9, 6, 8]
la[2] = 5

jupman.pytut()<jupyter_output><empty_output><jupyter_text>Come vedi, in questo non vengono create regioni di memoria nuove, semplicemente si va a sovrascrivere una cella esistente.   Esercizio - Un parcheggio intasatoSei l'amministratore del condominio "La Gioia Pitonica". Ogni appartamento ha uno o due posti auto assegnati e ciascuno è numerato da `1` a `11`. La seguente è il parcheggio attuale, e come si può vedere ci sono tre buchi non assegnati, perchè gli appartamenti `3`, `4` e `7` non hanno più un affittuario.<jupyter_code>parcheggi = ["Carlo", "App.3", "Ernesto", "App.4", "App.7", "Pam", "Giovanna", "Camilla", "Giorgia", "Jessica", "Jim"]<jupyter_output><empty_output><jupyter_text>Per mantenere l'ordine decidi che è il caso di compattare le assegnazioni e di lasciare i posti vuoti tutti in fondo (può essere comodo per far parcheggiare i traslocatori!)Scrivi del codice per MODIFICARE `parcheggi` in modo che risulti:```python>>> print(parcheggi)['Carlo', 'Jim', 'Ernesto', 'Pam', 'Giorgia', 'Pam', 'Giovanna', 'Camilla', 'Apt.3', 'Apt.4', 'Apt.7']```* **NON** creare nuove liste* Assegna ogni elemento uno per volta* supponi `parcheggi` abbia lunghezza fissa e che i posti non assegnati siano sempre 3 e in posizione fissa ![parking-jam](img/parking-jam.png)<jupyter_code>#jupman-purge-output
parcheggi = ["Carlo", "App.3", "Ernesto", "App.4", "App.7", "Pam", "Giovanna", "Camilla", "Giorgia", "Jessica", "Jim"]
#parcheggi = ["Cristian", "App.3", "Edgar", "App.4", "App.7", "Pamela", "Giusy", "Cristina", "Gaia", "Jessie", "John"]

# scrivi qui
parcheggi[1] = "Jim"
parcheggi[-3] = "Apt.3"
parcheggi[3] = "Pam"
parcheggi[-2] = "Apt.4"
parcheggi[4] = "Giorgia"
parcheggi[-1] = "Apt.7"

print(parcheggi)<jupyter_output>['Carlo', 'Jim', 'Ernesto', 'Pam', 'Giorgia', 'Pam', 'Giovanna', 'Camilla', 'Apt.3', 'Apt.4', 'Apt.7']<jupyter_text>Mutare liste condivise**ATTENZIONE: L'ARGOMENTO CHE SEGUE E' CAUSA DEL 90% DEGLI ERRORI DI PROGRAMMAZIONE !!!**    **LEGGI BENE !!!**Cosa succede quando associamo a due variabili lo stesso identico oggetto mutabile, come per esempio una lista, e poi usando una delle due variabili mutiamo l'oggetto? Guardiamo un esempio - per prima cosa, alla variabile `la` associamo la lista `[7,9,6]`:<jupyter_code>la = [7,9,6]<jupyter_output><empty_output><jupyter_text>Adesso definiamo una nuova variabile `lb`, e associamogli come valore _lo stesso valore_ già associato alla variabile `la`. Nota bene: qua NON stiamo creando nuove liste !<jupyter_code>lb = la    
print(la)  # la è sempre lo stesso
print(lb)  # lb è la stessa lista associata a la<jupyter_output>[7, 9, 6]<jupyter_text>Proviamo a modificare una cella di `lb`, mettendo `5` nella cella all'indice `0`:<jupyter_code>lb[0] = 5<jupyter_output><empty_output><jupyter_text>Se proviamo a stampare le variabili `la` ed `lb`, Python andrà a guardare i valori associati a ciascuna variabile. Dato che il valore è la stessa identica lista (che risiede nella stessa identica regione di memoria ), in entrambi i casi vedrai la modifica appena fatta !<jupyter_code>print(la)
print(lb)<jupyter_output>[5, 9, 6]<jupyter_text>Guardiamo meglio che succede in Python Tutor:<jupyter_code>la = [7,9,6]
lb = la
lb[0] = 5 
print('la è', la)
print('lb è', lb)

jupman.pytut()<jupyter_output>la è [5, 9, 6]
lb è [5, 9, 6]<jupyter_text>Guardiamo la differenza se invece creiamo esplicitamente una lista uguale a `la`. In questo caso avremo due regioni di memoria distinte e la NON sarà modificato:<jupyter_code>la = [7,9,6]
lb = [7,9,6]
lb[0] = 5 
print('la è', la)
print('lb è', lb)

jupman.pytut()<jupyter_output>la è [7, 9, 6]
lb è [5, 9, 6]<jupyter_text>**DOMANDA**: Dopo l'esecuzione di questo codice, cosa verrà stampato? Quante liste ci saranno effettivamente in memoria?Prova a disegnare **SU CARTA** quello che succede in memoria, e poi confronta con il risultato in Python Tutor!```pythonla = [8,7,7]lb = [9,6,7,5]lc = lbla = lbprint('la è', la)print('lb è', lb)print('lc è', lc)``` **RISPOSTA**: Viene stampato ```la è [9, 6, 7, 5]lb è [9, 6, 7, 5]lc è [9, 6, 7, 5]```perchè ```pythonla = [8,7,7]lb = [9,6,7,5] la variabile lc viene associata alla stessa identica lista di lb. lc = lb           la variabile la viene associata alla stessa identica lista di lb.  La lista precedentemente associata a la viene persala = lb```<jupyter_code>la = [8,7,7]
lb = [9,6,7,5]
lc = lb
la = lb
#print('la è', la)
#print('lb è', lb)
#print('lc è', lc)
jupman.pytut()<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Guarda il codice seguente. Dopo la sua esecuzione, cosa produrrà la stampa di `la`, `lb` ed `lc` ? Prova a disegnare **SU CARTA** quello che succede in memoria, e poi confronta con il risultato in Python Tutor!```pythonla = [7,8,5]lb = [6,7]lc = lblb = lalc[0] = 9print('la è', la)print('lb è', lb)print('lc è', lc)``` **RISPOSTA**: La stampa produrrà```la è [7, 8, 5]lb è [7, 8, 5]lc è [9, 7]```perchè :``` pythonla = [7,8,5]lb = [6,7] la variabile lc viene assegnata alla stessa lista di lb [6,7]lc = lb     la variabile lb viene associata alla stessa lista di la [7,8,5].  Questo non cambia l'assegnazione di lc, che resta associato a [6,7] !lb = la     Modifica il primo elemento della lista associata a lc che da [6,7] diventa [9,7]lc[0] = 9print('la è', la)print('lb è', lb)print('lc è', lc)```<jupyter_code>la = [7,8,5]
lb = [6,7]
lc = lb
lb = la
lc[0] = 9
#print('la è', la)
#print('lb è', lb)
#print('lc è', lc)

jupman.pytut()<jupyter_output><empty_output><jupyter_text>Liste di stringhe Abbiamo detto che in una lista possiamo mettere qualunque oggetto, per esempio delle stringhe:<jupyter_code>verdure = ['pomodori', 'verze', 'carote', 'cavoli']<jupyter_output><empty_output><jupyter_text>Proviamo ad estrarre una verdura scrivendo questa espressione:<jupyter_code>verdure[2]<jupyter_output><empty_output><jupyter_text>Ora, l'espressione precedente ci ha prodotto il risultato `'carote'`, che sappiamo essere una stringa. Questo ci suggerisce che possiamo usare l'espressione esattamente come se fosse una stringa. Supponiamo che vogliamo ottenere il primo carattere della stringa `'carote'`, avendo direttamente la stringa scriveremmo così:<jupyter_code>'carote'[0]<jupyter_output><empty_output><jupyter_text>Ma se la stringa è racchiusa nella lista di prima, potremmo fare direttamente così:<jupyter_code>verdure[2][0]<jupyter_output><empty_output><jupyter_text>Esercizio - sigleData una lista con sigle di esattamente 4 capoluoghi in minuscolo, scrivere del codice che crea una NUOVA lista contente le stesse sigle in caratteri tutti maiuscoli. * il tuo codice deve funzionare con qualunque lista di 4 capoluoghi* suggerimento: se non ti ricordi il metodo giusto, [guarda qua](https://it.softpython.org/strings/strings3-sol.html)Esempio 1 - dato:```pythonsigle = ['tn','mi','to','ro']```il tuo codice deve stampare```python['TN', 'MI', 'TO', 'RO']```Esempio 2 - dato:```pythonsigle = ['pa','ge','ve', 'aq']```il tuo codice deve stampare:```python['PA', 'GE', 'VE', 'AQ']```![plate](img/plate.png)<jupyter_code>#jupman-purge-output
sigle = ['tn','mi','to','ro']

# scrivi qui

print([sigle[0].upper(), sigle[1].upper(), sigle[2].upper(), sigle[3].upper()])<jupyter_output>['TN', 'MI', 'TO', 'RO']<jupyter_text>Esercizio - giochiData una lista `giochi` di esattamente 3 stringhe, scrivi del codice che MODIFICA la lista in modo che contenga solo i primi caratteri di ciascuna stringa* Il tuo codice deve funzionare con qualunque lista di esattamente 3 stringheEsempio - data:```pythongiochi = ["Monopoli", "RISIKO", "Tombola"]```Dopo l'esecuzione del tuo codice, deve risultare:```python>>> print(giochi)["M","R","T"]```* **NON** creare liste nuove (quindi niente assegnazioni come `giochi = ` ...)<jupyter_code>#jupman-purge-output
giochi = ["Monopoli", "RISIKO", "Tombola"]                     # ['M','R','T']
#giochi = ["Non t'arrabbiare", "Gioco dell'oca", "Scarabeo"]   # ['N','G','S']

# scrivi qui

giochi[0] = giochi[0][0]
giochi[1] = giochi[1][0]
giochi[2] = giochi[2][0]
print(giochi)<jupyter_output>['M', 'R', 'T']<jupyter_text>SlicePossiamo estrarre delle sequenze dalle liste usando le slice. Una slice si produce aggiungendo delle parentesi quadre alla destra della lista e mettendo nelle quadre l'indice di partenza (INCLUSO), seguito da due punti `:`, seguito dall'indice di fine (ESCLUSO). Funziona esattamente come per le stringhe: in quel caso la quadra produceva una nuova stringa, in questo si produce una NUOVA lista. Vediamo un esempio:<jupyter_code>#0  1  2  3  4  5  6  7  8  9
la = [40,30,90,80,60,10,40,20,50,60]
la[3:7]<jupyter_output><empty_output><jupyter_text>Abbiamo estratto una NUOVA lista `[80, 60, 10, 40]` a partire della lista `la` partendo dall'indice `3` INCLUSO fino all'indice `7` ESCLUSO. Possiamo vedere che la lista originale si è preservata:<jupyter_code>la<jupyter_output><empty_output><jupyter_text>Verifichiamo cosa succede con Python Tutor, assegnando la nuova lista ad una variabile `lb`:<jupyter_code>#     0  1  2  3  4  5  6  7  8  9
la = [40,30,90,80,60,10,40,20,50,60]
lb = la[3:7]

jupman.pytut()<jupyter_output><empty_output><jupyter_text>Noterai che compare una NUOVA regione di memoria, associata alla variabile `lb`.  Slice - limitiQuando operiamo con le slice dobbiamo stare attenti ai limiti degli indici. Vediamo come si comportano:<jupyter_code>#0  1  2  3  4  
[50,90,70,80,60][0:3]  # da indice 0 *incluso* a 3 *escluso*
#0  1  2  3  4  
[50,90,70,80,60][0:4]  # da indice 0 *incluso* a 4 *escluso*
#0  1  2  3  4  
[50,90,70,80,60][0:5]  # da indice 0 *incluso* a 5 *escluso*
#0  1  2  3  4  
[50,90,70,80,60][0:6]   # se andiamo oltre la lunghezza della lista Python non si arrabbia
#0  1  2  3  4  
[50,90,70,80,60][8:12]   # anche se partiamo da indici inesistenti Python non si arrabbia<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Questa espressione```python[][0:8]```1. produce un risultato (quale?)2. produce un errore (quale?) **RISPOSTA**: data una lista vuota, stiamo cercando di ottenere una sottolista che va dall'indice 0 INCLUSO all'indice 8 ESCLUSO. Come abbiamo visto prima, se sforiamo Pyhton non si arrabbia, quindi semplicemente non trovando elementi ci ritorna una lista vuota. **DOMANDA**: Questa espressione```python[][3:8]```1. produce un risultato (quale?)2. produce un errore (quale?) **RISPOSTA**: data una lista vuota, stiamo cercando di ottenere una sottolista che va dall'indice 3 INCLUSO all'indice 8 ESCLUSO. Come abbiamo visto prima, se sforiamo anche dal limite sinistro Pyhton non si arrabbia, quindi semplicemente non trovando elementi ci ritorna una lista vuota. **DOMANDA**: se `x` è una lista qualsiasi (anche vuota), questa espressione cosa fa? Può dare errore? o ritorna qualcosa di utile? ```pythonx[0:len(x)]``` **RISPOSTA**: Ritorna sempre una NUOVA copia dell'intera lista, perchè parte da indice 0 _INCLUSO_ e finisce a indice `len(x)` _ESCLUSO_Funziona anche con la lista vuota, perchè `[][0:len([])]` equivale a `[][0:0]`  cioè sottolista da 0 _incluso_ a 0 _escluso_, quindi non prendiamo nessun carattere e non sforiamo i limiti della lista. In realtà, come abbiamo visto prima, anche se sforassimo Python non avrebbe problemi.  Esercizio - La treccia mochenaCome ben sai nella valle dei Mocheni vi è una meravigliosa specialità di cucina pasticciera: si tratta della famosa treccia Mochena.Ad un'occhiata frettolosa la treccia mochena potrebbe apparire come uno sfilatino, lungo tra i 30 e 60 cm al cui interno vengono messi un mix di ingredienti insieme alla mirabolante e segretissima crema.Insieme ai tuoi amici Camilla e Giorgio hai acquistato una treccia farcita con granella di noci, mirtilli e ribes rossi.Ma a te non piacciono le noci e a Giorgio non piacciono i mirtilli!Scrivi del codice per mettere nelle variabili `mio`, `giorgio` e `camilla` delle liste ottenute da `treccia`, e STAMPA il risultato:```pythonMio: ['m', 'm', 'm', 'm', 'm', 'm'] Giorgio: ['n', 'n', 'n', 'n', 'n'] Camilla: ['r', 'r', 'r', 'r']```* supponi la `treccia` abbia lunghezza e numero di ingredienti fissi<jupyter_code>#jupman-purge-output

#           Noci                     Mirtilli                     Ribes
treccia = ['n', 'n', 'n', 'n', 'n', 'm', 'm', 'm', 'm', 'm', 'm', 'r', 'r', 'r', 'r', 'r']
#treccia = ['N', 'N', 'N', 'N', 'N', 'M', 'M', 'M', 'M', 'M', 'M', 'R', 'R', 'R', 'R', 'R']


# scrivi qui
mio_piatto = treccia[5:11]
giorgio_piatto = treccia[0:5]
camilla_piatto = treccia[12:16]
print("Mio: %s \nGiorgio: %s \nCamilla: %s" % (mio_piatto, giorgio_piatto, camilla_piatto))<jupyter_output>Mio: ['m', 'm', 'm', 'm', 'm', 'm'] 
Giorgio: ['n', 'n', 'n', 'n', 'n'] 
Camilla: ['r', 'r', 'r', 'r']<jupyter_text>Slice - omissione limiti Volendo, è possibile omettere l'indice di partenza, in tal caso Python supporrà sia 0:<jupyter_code>#0  1  2  3  4  5  6  7  8  9
[90,60,80,70,60,90,60,50,70][:3]<jupyter_output><empty_output><jupyter_text>E' anche possibile omettere l'indice di fine, in tal caso Python estrarrà fino alla fine della lista:<jupyter_code>#0  1  2  3  4  5  6  7  8  9
[90,60,80,70,60,90,60,50,70][3:]<jupyter_output><empty_output><jupyter_text>Omettendo entrambi gli indici si ottiene l'intera lista:<jupyter_code>#0  1  2  3  4  5  6  7  8  9
[90,60,80,70,60,90,60,50,70][:]<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Cosa stamperà questo codice ? `la` sarà modificato oppure no?```pythonla = [7,8,9]lb = la[:]lb[0] = 6print('la =',la)print('lb =',lb)``` **RISPOSTA**: `lb = la[:]` crea una NUOVA lista contente tutti gli elementi che stanno in `la`. Quindi quando scriviamo `lb[0] = 6` stiamo modificando solo la regione di memoria associat a `lb`. Se osservi in Python Tutor, vedrai che `la` e `lb` puntano a regioni di memoria differenti:<jupyter_code>la = [7,8,9]
lb = la[:]
lb[0] = 6
#print('la =',la)
#print('lb =',lb)

jupman.pytut()<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Per ciascuna delle espressioni seguenti, prova a indovinare quale valore produce, o se da errore.1.  ```python        [9,7,8,6][1:1]    ```1.  ```python        [9,7,8,6][1:2]    ```1.  ```python        [9,7,8,6][2:3][0]    ```1.  ```python    [][]    ```1.  ```python    [][:]    ```1.  ```python    [3][:]    ```1.  ```python        [:][]    ```  Esercizio - La chitarra scordataIn soffitta hai trovato una vecchia chitarra che girava per casa quando eri una bambina. Adesso che ti sei laureata in ingegneria della gestione del suono provi a strimpellarla mentre un sensore misura la nota prodotta.Il sensore è un microfono e ogni decimo di secondo registra la nota principale che ha rilevato.Con questo test ti accorgi di un fenomeno molto bizzarro. Alcune delle corde della chitarra appena vengono suonate hanno un comportamento altalenante ma poi si sintonizzano su una nota precisa fino alla fine:```python    "do, re, mi, do, sol, do, do, do, do, do, do, do, ..."``` Altre corde invece fanno l'opposto:```python"sol, sol, sol, sol, sol, sol, sol, sol, sol, re, mi, fa, sol, do, do, sol, re, mi, mi, re, ..."```Scrivi del codice per tagliare l'output del sensore e ottenere così solo le sequenze di note continue e corrette. Alla fine deve STAMPARE:```python['do', 'do', 'do', 'do', 'do', 'do', 'do']['sol', 'sol', 'sol', 'sol', 'sol', 'sol']['fa', 'fa', 'fa', 'fa', 'fa', 'fa', '...']['re', 're', 're', 're', 're', 're', '...']```<jupyter_code>#jupman-purge-output
corda1 = ['do', 'do', 'do', 'do', 'do', 'do', 'do', 're', 'sol', 'fa', 'si', 'si', 'do', 'si', '...']
corda2 = ['sol', 'sol', 'sol', 'sol', 'sol', 'sol', 're', 're', 'la', 'la', 'si', 'fa', 'si', '...']
corda3 = ['do', 'la', 'fa', 'mi', 'la', 'do', 'si', 'fa', 'fa', 'fa', 'fa', 'fa', 'fa', 'fa', '...']
corda4 = ['si', 'si', 'mi', 'sol', 'la', 'la', 'mi', 're', 're', 're', 're', 're', 're', '...']

# scrivi qui
corda1_pulito = corda1[:7]
corda2_pulito = corda2[:6]
corda3_pulito = corda3[8:]
corda4_pulito = corda4[7:]

print(corda1_pulito)
print(corda2_pulito)
print(corda3_pulito)
print(corda4_pulito)<jupyter_output>['do', 'do', 'do', 'do', 'do', 'do', 'do']
['sol', 'sol', 'sol', 'sol', 'sol', 'sol']
['fa', 'fa', 'fa', 'fa', 'fa', 'fa', '...']
['re', 're', 're', 're', 're', 're', '...']<jupyter_text>Slice - limiti negativiVolendo è anche possibile impostare limiti negativi, per quanto non sia sempre molto intuitivo.<jupyter_code>#0  1  2  3  4  5  6    
[70,40,10,50,60,10,90][3:0]   # da indice 3 a indici positivi <= 3 non produce nulla
#0  1  2  3  4  5  6    
[70,40,10,50,60,10,90][3:1]   # da indice 3 a indici positivi <= 3 non produce nulla
#0  1  2  3  4  5  6     
[70,40,10,50,60,10,90][3:2]  # da indice 3 a indici positivi <= 3 non produce nulla
#0  1  2  3  4  5  6     
[70,40,10,50,60,10,90][3:3]  # da indice 3 a indici positivi <= 3 non produce nulla<jupyter_output><empty_output><jupyter_text>Vediamo cosa succede con indici negativi:<jupyter_code># 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][3:-1]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][3:-2]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][3:-3]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][3:-4]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][3:-5]<jupyter_output><empty_output><jupyter_text>E' anche possibile partire da un indice negativo e arrivare ad uno positivo: finchè il primo indice marca una posizione antecedente a quella del secondo indice, viene restituito qualcosa:<jupyter_code># 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][-7:3]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][-6:3]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][-5:3]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][-4:3]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][-3:3]
# 0  1  2  3  4  5  6   
#-7 -6 -5 -4 -3 -2 -1   
[70,40,10,50,60,10,90][-2:3]<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Per ciascuna delle espressioni seguenti, prova a indovinare quale valore produce, o se da errore.1.  ```python    [9,7,8,6][0:-2]    ```1.  ```python        [0:-2][9,7,8,6]    ```1.  ```python        [5,7,9][1:-1]    ```1.  ```python        [][-13:-17]    ```1.  ```python        [9,7,8,6][-4:-1]    ```1.  ```python        [9,7,8,6][-5:-1]    ```1.  ```python        [9,7,8,6,10,32][-3:1]    ```1.  ```python        [9,7,8,6,10,32][-3:5]    ```      Esercizio - lo scontrinoPer controllare le tue spese vuoi scrivere un software che tenga traccia di tutto ciò che compri. E cercare di ridurre le spese inutili.Grazie ad una libreria ti basta scattare una foto con lo smartphone allo scontrino e il testo verrà letto in maniera automatica.Sai che **tutti** gli scontrini seguono lo stesso schema: nome negozio, data, "articoli acquistati", 1 riga per prodotto, totale, ringraziamenti.Scrivi del codice per creare una NUOVA lista con solamente le righe degli articoli, per esempio:```['Pettine per pitoni               12,00€', 'Accendisigari da immersione      23,00€', 'Coriandoli piombo anti-vento      4,99€', 'Scarpe trasparenti da casa       35,56€', 'Insaporitore per insalata         1,12€']```<jupyter_code>#jupman-purge-output
scontrino = ["<NAME>",
             "21 Luglio 2021 14:54",
             "Articoli acquistati",
             "Pettine per pitoni               12,00€",
             "Accendisigari da immersione      23,00€",
             "Coriandoli piombo anti-vento      4,99€",
             "Scarpe trasparenti da casa       35,56€",
             "Insaporitore per insalata         1,12€",
             "Totale 56,66€",
             "Grazie per aver fatto acquisti in questo negozio!"
            ]

# scontrino = ["Eleganz", "3 Gennaio 2020 12:5", "<NAME>", 
#              "Zeppe con acquario e pesci  342,00€",   
#              "Abito Completo 'Elvis'      20.000,00€",
#              "Totale 20.000,342€","Grazie per aver fatto acquisti in questo negozio!"]


# scrivi qui
articoli = scontrino[3:-2]
from pprint import  pprint
pprint(articoli)<jupyter_output>['Pettine per pitoni               12,00€',
 'Accendisigari da immersione      23,00€',
 'Coriandoli piombo anti-vento      4,99€',
 'Scarpe trasparenti da casa       35,56€',
 'Insaporitore per insalata         1,12€']<jupyter_text>Slice - passoE' anche possibile specificare un terzo parametro detto 'passo' per indicare a python di quante celle spostarsi ad ogni lettura. Qui per esempio partiamo dall'indice 3 per arrivare all'indice 9 escluso, **saltando di 2**:<jupyter_code># 0 1  2  3  4  5  6  7  8  9
[ 0,10,20,30,40,50,60,70,80,90][3:9:2]<jupyter_output><empty_output><jupyter_text>Tutta la sequenza, saltando di 3:<jupyter_code># 0 1  2  3  4  5  6  7  8  9
[ 0,10,20,30,40,50,60,70,80,90][0:10:3]<jupyter_output><empty_output><jupyter_text>Possiamo anche omettere i limiti per ottenere l'espressione equivalente:<jupyter_code># 0 1  2  3  4  5  6  7  8  9
[ 0,10,20,30,40,50,60,70,80,90][::3]<jupyter_output><empty_output><jupyter_text>Slice - modificaSupponiamo di avere la lista<jupyter_code>#0  1  2  3  4  5  6  7
la = [30,40,80,10,70,60,40,20]<jupyter_output><empty_output><jupyter_text>e di voler cambiare le celle di `la` dall'indice `3` INCLUSO all'indice `6` ESCLUSO in modo che contengano i numeri presi dalla lista `[91,92,93]`. Possiamo farlo con questa notazione speciale che ci consente di scrivere una slice _alla sinistra_ dell'operatore `=`:<jupyter_code>la[3:6] = [91,92,93]
la<jupyter_output><empty_output><jupyter_text>In questo esempio leggermente più complesso verifichiamo in Python Tutor che viene effettivamente modificata la regione di memoria originale:<jupyter_code>#     0  1  2  3  4  5  6  7
la = [30,40,80,10,70,60,40,20]
lb = la 
lb[3:6] = [91,92,93]

jupman.pytut()<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Guarda il seguente codice - cosa produce?```pythonla = [9,6,5,8,2]la[1:4] = [4,7,0]print(la)```1. modifica `la` (come?)2. un errore (quale?) **RISPOSTA**: La 1 - MODIFICA `la` così:```python 0  1  2  3  4[ 9, 4, 7, 0, 2]```quindi dall'indice `1` INCLUSO all'indice `4` ESCLUSO **DOMANDA**: Guarda il seguente codice. Cosa produce?```pythonla = [7,6,8,4,2,4,2,3,1]i = 3lb = la[0:i]la[i:2*i] = lbprint(la)```1. modifica `la` (come?)2. un errore (quale?) **RISPOSTA**: La 1 - modifica `la` copiando le prime `i` celle nelle successive.  Esercizio - I banditi della ferrovia ![ferrovia](img/railroad-outlaws.png) Stati Uniti - 13 Maggio 1857La colonizzazione dei territori del west è un duro lavoro ma qualcuno deve pur farlo. Le montagne sono zeppe di minerali rari e di animali pulciosi da trasformare in preziose pellicce per le nobildame d'Europa. Ma come sempre, dove ci sono grandi ricchezze, arrivano anche grandi banditi.Sei il capostazione della stazione di Denver e devi gestire i treni. Ci sono tre direttrici principali, Colorado Springs, Fort Collins e New York:* da Colorado Springs arrivano sempre esattamente 1 vagone di carbone, 3 di minerali e 3 di persone **alternati*** da Fort Collins arrivano sempre esattamente 2 vagoni di carbone, 2 di persone e 2 di bestiameQuando i treni arrivano a Denver, il loro contenuto viene trasferito nei vagoni vuoti del treno per New York così:* per impedire il compiersi di furti al treno, tutti i vagoni preziosi vanno posizionati **vicino alla locomotiva*** il bestiame **va sempre messo dietro** le persone, perchè per quanto l'igiene nel west sia carente è comunque più facile pretendere che gli umani si lavino piuttosto che il bestiameScrivi del codice che MODIFICA `new_york` copiando le stringhe da `colorado` e `fort`.* **MINIMIZZA il numero di assegnazioni!** (la soluzione migliore ha solamente due assegnazioni!)Esempio - dati:<jupyter_code>colorado = ["locomotiva CS","carbone", "cowboy",    "oro","minatori",   "oro","cowboy","argento"]
fort     = ["locomotiva FC","carbone","carbone","signori",    "dame","mucche","cavalli"]
new_york = ["locomotiva NY","carbone",       "",       "",        "",      "",       "",      "", "","",""]<jupyter_output><empty_output><jupyter_text>dopo il tuo codice deve risultare:```python>>> print(new_york)['locomotiva NY', 'carbone', 'oro', 'oro', 'argento', 'cowboy', 'minatori', 'cowboy', 'signori', 'dame', 'mucche', 'cavalli']```<jupyter_code>#jupman-purge-output
           # 0               1         2          3        4          5        6        7         8  9  10
colorado = ["locomotiva CS","carbone", "cowboy",    "oro","minatori",   "oro","cowboy","argento"]
fort     = ["locomotiva FC","carbone","carbone","signori",    "dame","mucche","cavalli"]
new_york = ["locomotiva NY","carbone",       "",       "",        "",      "",       "",      "", "","",""]

# scrivi qui
new_york[2:5] = colorado[3::2]
new_york[5:] = colorado[2::2]
new_york[8:] = fort[3:]
print(new_york)<jupyter_output>['locomotiva NY', 'carbone', 'oro', 'oro', 'argento', 'cowboy', 'minatori', 'cowboy', 'signori', 'dame', 'mucche', 'cavalli']<jupyter_text>Liste di liste**NOTA: Parleremo molto più nel dettaglio delle liste di liste nel tutorial** [Matrici - liste di liste](https://it.softpython.org/matrices-lists/matrices-lists-sol.html), questa è solo un'introduzione sommaria.Le considerazioni viste per le liste di stringhe valgono anche per una lista di liste:<jupyter_code>coppie = [          # lista esterna
            [67,95],    # lista interna ad indice 0
            [60,59],    # lista interna ad indice 1
            [86,75],    # lista interna ad indice 2
            [96,90],    # lista interna ad indice 3
            [88,87],    # lista interna ad indice 4
         ]<jupyter_output><empty_output><jupyter_text>Se vogliamo estrarre il numero `90`, dobbiamo prima estrarre la sottolista all'indice `3`:<jupyter_code>coppie[3]   # NOTA: il risultato di questa espressione è una lista<jupyter_output><empty_output><jupyter_text>e quindi dalla sottolista estratta (che ha solo due elementi) possiamo recuperare il numero all'indice `0`:<jupyter_code>coppie[3][0]<jupyter_output><empty_output><jupyter_text>e all'indice `1`:<jupyter_code>coppie[3][1]<jupyter_output><empty_output><jupyter_text>Esercizio - coppie1. Scrivi il codice per recuperare e stampare il numero `86`, il `67` e l'`87`2. Date una riga con indice `i` e una colonna `j`, stampare il numero alla riga `i` e colonna `j` moltiplicato per il numero alla riga successiva e stessa colonnaDopo il tuo codice, dovresti veder stampato:```punto 1: 86 67 87punto 2: 7830```<jupyter_code>coppie = [           # lista esterna
            [67,95],    # lista interna ad indice 0
            [60,59],    # lista interna ad indice 1
            [86,75],    # lista interna ad indice 2
            [96,90],    # lista interna ad indice 3
            [88,87],    # lista interna ad indice 4
         ]

i = 3
j = 1

# scrivi qui

#print("punto 1:", coppie[2][0], coppie[0][0], coppie[4][1])
#print()
#print("punto 2:", coppie[i][j]*coppie[i+1][j])<jupyter_output><empty_output><jupyter_text>Esercizio - Gloria ai Gladiatori!I gladiatori lottano per la gloria della battaglia e per il divertimento dell'imperatore e del popolo!Non tutti i gladiatori riescono a... beh... combattere lo stesso numero di battaglie.Per ogni combattimento, ogni gladiatore riceve un compenso in sesterzi (in caso non sia sopravissuto, verrà offerto al suo patrono...)Alla fine dei giochi, l'imperatore getta un premio in sesterzi al gladiatore favorito. L'imperatore ha però scarsa mira e le sue deboli braccia non gli consentono di tirare tutto in un colpo solo, quindi finisce sempre per tirare metà malloppo al gladiatore giusto e metà al gladiatore subito dopo.* **NOTA**: L'imperatore **non può** premiare l'ultimo della lista perchè è troppo lontanoData un  `premio` e una lista `gladiatori` di sottoliste di lunghezza arbitraria, e un gladiatore ad indice `i`, scrivi del codice che MODIFICA le sottoliste di `gladiatori` alla riga `i` e alla successiva in modo che l'ultimo elemento di entrambe le liste venga aumentato di metà `premio`.* il tuo codice deve funzionare con qualunque `premio`, `gladiatori` e qualunque `i`**Esempio - dati**:  ![gladiatori](img/gladiators.png) Dopo il tuo codice, scrivendo (usiamo `pprint` perchè così la stampa avverrà su più linee)```pythonfrom pprint import pprintpprint(gladiatori,width=30)```deve stampare:```python[[67, 95], [60, 23, 23, 13, 79], [86, 95], [96, 90, 92], [88, 87]]```<jupyter_code>#jupman-purge-output
premio = 40                      # sesterzi

gladiatori = [                   # lista esterna
               [67,95],          # lista interna ad indice 0
               [60,23,23,13,59], # lista interna ad indice 1
               [86,75],          # lista interna ad indice 2
               [96,90,92],       # lista interna ad indice 3
               [88,87],          # lista interna ad indice 4
             ]

i = 1                            # gladiatore da premiare

# scrivi qui
gladiatori[i][-1]   += premio // 2    
gladiatori[i+1][-1] += premio // 2

from pprint import pprint
pprint(gladiatori,width=30)<jupyter_output>[[67, 95],
 [60, 23, 23, 13, 79],
 [86, 95],
 [96, 90, 92],
 [88, 87]]<jupyter_text>Operatore inPer verificare se un oggetto è contenuto in una lista, possiamo usare l'operatore `in`. Nota che il risultato di questa espressione è un booleano:<jupyter_code>9 in [6,8,9,7]
5 in [6,8,9,7]
"mela" in ["anguria","mela","banana"]
"carota" in ["anguria","banana","mela"]<jupyter_output><empty_output><jupyter_text>Non abusare `in`      **ATTENZIONE**: `in` **viene spesso usato in modo errato / inefficiente**Chiediti sempre:    1. la lista potrebbe _non_ contenere l'elemento cercato? Ricordati di gestire anche questo caso!2. `in` compie una ricerca in tutta la lista, che può essere inefficiente: è proprio necessaria, o sappiamo già l'intervallo in cui cercare? 3. se vogliamo sapere se un `elemento` è in una posizione nota a priori (es `3`), `in` non ci serve, basta scrivere `lista[3] == elemento`. Usando `in` potremmo trovare elementi duplicati che stanno _prima_ o _dopo_ di quello che vogliamo verificare! **DOMANDA**: Questa espressione cosa restituisce? `True` o `False`?```pythonTrue in [ 5 in [6,7,5],          2 in [8,1]        ]``` **RISPOSTA**: Restituisce `True` perchè ```python[ 5 in [6,7,5],  2 in [8,1]]```rappresenta una lista di due elementi. Ogni elemento è una espressione con `in`, che viene valutata. Nel primo caso, `5 in [6,7,5]` risulta `True`, nel secondo `2 in [8,1]` risulta `False`. Quindi la lista finale diventa `[True, False]` e scrivendo `True in [True, False]` si ottiene `True`  not inPossiamo scrivere la verifica di **non** appartenza in due forme:**Forma 1**:<jupyter_code>"carota" not in ["anguria","banana","mela"]
"anguria" not in ["anguria","banana","mela"]<jupyter_output><empty_output><jupyter_text>**Forma 2:**<jupyter_code>not "carota" in ["anguria","banana","mela"]
not "anguria" in ["anguria","banana","mela"]<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Data qualunque elmento `x` e  lista `y` , la seguente espressione cosa restituisce?```pythonx in y and not x in y```1. `False`2. `True`3. `False` oppure `True` a seconda dei valori di `x` e `y`4. un errore **RISPOSTA**: la 1. Restituisce `False`, perchè internamente python 'Parentesizza' l'espressione così:```python(x in y) and (not x in y)```e un elemento non può contemporaneamente essere e non essere nella stessa lista. **DOMANDA**: Per ciascuna delle seguenti espressioni, provare a indovinare il risultato1.  ```python    3 in [3]    ```1.  ```python        [4,5] in [1,2,3,4,5]    ```1.  ```python        [4,5] in [[1,2,3],[4,5]]    ```1.  ```python        [4,5] in [[1,2,3,4],[5,6]]    ```1.  ```python        'a' in ['prova'[-1]]    ```1.  ```python        'ghe' in 'paghe'[1:4]    ```1.  ```python        [] in [[[]]]    ```1.  ```python        [] in [[]]    ```1.  ```python        [] in ["[]"]    ``` **DOMANDA**: Per ciascuna delle seguenti espressioni, indipendentemente dal valore di `x`, dire se risulta sempre `True` :1.  ```python    x in x    ```1.  ```python        x in [x]    ```1.  ```python        x not in []    ```1.  ```python        x in [[x]]    ```1.  ```python    x in [[x][0]]    ```1.  ```python        (x and y) in [x,y]    ```1.  ```python    x in [x,y] and y in [x,y]    ```  Esercizio - ortaggiDate le lista  `ortaggi` di esattamente 5 stringhe e la lista di stringhe `frutta`, MODIFICARE la variabile `ortaggi` in modo che in ogni cella vi sia `True` se l'ortaggio è un frutto oppure `False` altrimenti.* il tuo codice deve funzionare con qualsiasi lista di 5 stringhe `ortaggi` e qualsiasi lista `frutta`Esempio - dati:```pythonortaggi = ["carota",           "cavolfiore",           "mela",           "melanzana",           "anguria"]frutta = ["anguria","banana","mela",]```dopo l'esecuzione del tuo codice deve stampare:```python>>> print(ortaggi)[False, False, True, False, True]```<jupyter_code>ortaggi = ["carota",
           "cavolfiore",
           "mela",
           "melanzana",
           "anguria"]

frutta = ["anguria","banana","mela",]

# scrivi qui

ortaggi = [ortaggi[0] in frutta,
           ortaggi[1] in frutta,
           ortaggi[2] in frutta,
           ortaggi[3] in frutta,
           ortaggi[4] in frutta,
]

#print(ortaggi)<jupyter_output><empty_output><jupyter_text>Concatenazione di liste con +Date due liste `la` e `lb`, possiamo concatenarle con l'operatore `+` che produce una NUOVA lista:<jupyter_code>la = [70,60,80]
lb = [90,50]

la + lb<jupyter_output><empty_output><jupyter_text>Nota bene che l'operatore `+` produce una NUOVA lista, quindi `la` ed `lb` sono rimaste immutate:<jupyter_code>print(la)
print(lb)<jupyter_output>[90, 50]<jupyter_text>Vediamo meglio con Python Tutor:<jupyter_code>la = [70,60,80]
lb = [90,50]
lc = la + lb

print(la)
print(lb)
print(lc)

jupman.pytut()<jupyter_output>[70, 60, 80]
[90, 50]
[70, 60, 80, 90, 50]<jupyter_text>Esercizio - concatenazioneScrivere del codice che date due liste `la` e `lb`, mette nella lista `lc` gli ultimi due elementi di `la` e i primi due elementi di `lb`Esempio - date:```pythonla = [18,26,30,45,55]lb = [16,26,37,45]```dopo il tuo codice deve risultare:```>>> print(la)[18, 26, 30, 45, 55]>>> print(lb)[16, 26, 37, 45]>>> print(lc)[45, 55, 16, 26]```<jupyter_code>#jupman-purge-output
la = [18,26,30,45,55]
lb = [16,26,37,45]

# scrivi qui
lc = la[-2:] + lb[:2]
print(la)
print(lb)
print(lc)<jupyter_output>[18, 26, 30, 45, 55]
[16, 26, 37, 45]
[45, 55, 16, 26]<jupyter_text>**DOMANDA**: Per ciascuna delle seguenti espressioni, provare a indovinare il risultato    1.  ```python    [6,7,8] + [9]    ```1.  ```python        [6,7,8] + []    ```1.  ```python        [] + [6,7,8]    ```1.  ```python        [] + []    ```1.  ```python        [] + [[]]    ```1.  ```python        [[]]+[]    ```1.  ```python        [[]]+[[]]    ```1.  ```python        ([6] + [8])[0]    ```1.  ```python        ([6] + [8])[1]    ```1.  ```python        ([6] + [8])[2:]    ```1.  ```python        len([4,2,5])+len([3,1,2])    ```1.  ```python        len([4,2,5] + [3,1,2])    ```1.  ```python        [5,4,3] + "3,1"    ```1.  ```python        [5,4,3] + "[3,1]"    ```1.  ```python        "[5,4,3]" + "[3,1]"    ```1.  ```python        ["4","1","7"] + ["3","1"]    ```1.  ```python        list('coca') + ['c','o','l','a']    ```  min e maxUna lista è una sequenza di elementi, e come tale la possiamo passare alla funzione `min` o `max` per trovare rispettivamente il minimo o massimo elemento della lista.<jupyter_code>min([4,5,3,7,8,6])
max([4,5,3,7,8,6])<jupyter_output><empty_output><jupyter_text>**ATTENZIONE: MAI CHIAMARE VARIABILI** `min` **O** `max`Facendolo, finiresti per sovrascrivere le funzioni e al momento di chiamarle otterresti errori molto strani !     Notare che è anche possibile passare direttamente a `min` e `max` gli elementi da comparare senza includerli in una lista:<jupyter_code>min(4,5,3,7,8,6)
max(4,5,3,7,8,6)<jupyter_output><empty_output><jupyter_text>Ma se ne passiamo uno solo, senza includerlo in una lista, otterremo un errore: ```pythonmin(4)---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last) in ----> 1 min(4)TypeError: 'int' object is not iterable``` L'errore ci comunica che quando passiamo un solo argomento, Python si aspetta che sia una lista:<jupyter_code>min([4])<jupyter_output><empty_output><jupyter_text>A `min` e `max` possiamo anche passare stringhe, e ci verrà tornato il carattere alfabeticamente rispettivamente minore o maggiore :<jupyter_code>min("sportello")
max("sportello")<jupyter_output><empty_output><jupyter_text>Se passiamo una lista di stringhe, otterremo la stringa minore o maggiore in ordine lessicografico (per intenderci, quello dell'elenco telefonico):<jupyter_code>min(['il','marinaio','cammina','per','le','vie','del','porto'])
max(['il','marinaio','cammina','per','le','vie','del','porto'])<jupyter_output><empty_output><jupyter_text>**DOMANDA**: Per ciascuna delle seguenti espressioni, prova a indovinare il risultato (o se da un errore)    1.  ```python    max(7)    ```1.  ```python        max([7])    ```1.  ```python        max([5,4,6,2])    ```1.  ```python        max([min([7,3])])    ```1.  ```python        max([])    ```1.  ```python        max(2,9,3)    ```1.  ```python        max([3,2,5] + [9,2,3])    ```1.  ```python        max(max([3,2,5], max([9,2,3]))    ```1.  ```python        max(min(3,6), min(8,2))    ```1.  ```python        min(max(3,6), max(8,2))    ```1.  ```python        max(['a','b','d','c'])    ```1.  ```python        max(['barca', 'dado', 'aloa', 'cerchio'])    ```1.  ```python        min(['prova','','z','v'])    ```1.  ```python        max(['martello'[-1],'cacciavite'[-1],'brugola'[-1]])    ```1.  ```python        min(['martello'[-1],'cacciavite'[-1],'brugola'[-1]])    ```  sumCon `sum` possiamo sommare tutti gli elementi di una lista:<jupyter_code>sum([1,2,3])
sum([1.0, 2.0, 0.14])<jupyter_output><empty_output><jupyter_text>**ATTENZIONE: MAI CHIAMARE VARIABILI** `sum`Facendolo, finiresti per sovrascrivere la funzione e al momento di chiamarle otterresti errori molto strani !     **DOMANDA**:  Per ciascuna delle seguenti espressioni, prova a indovinare il risultato (o se da un errore)1.  ```python    sum[3,1,2]    ```1.  ```python    sum(1,2,3)    ```1.  ```python    la = [1,2,3]    sum(la) > max(la)    ```1.  ```python       la = [1,2,3]    sum(la) > max(la)*len(la)    ```1.  ```python    la = [4,2,6,4,7]    lb = [max(la), min(la), max(la)]    print(max(lb) != max(la))    ```  Esercizio - bilanciaData una lista di `n` numeri `bilancia` con `n` pari, scrivere del codice che stampa `True` se la somma di tutti i primi `n/2` numeri è uguale alla somma di tutti i successivi* il tuo codice deve funzionare per _qualunque_ lista di numeri Esempio 1 - dati:```pythonbilancia = [4,3,7,1,5,8]```dopo il tuo codice, deve stampare ```True```Esempio 2 - dati:```pythonbilancia = [4,3,3,1,9,8]```dopo il tuo codice, deve stampare ```False```<jupyter_code>bilancia = [4,3,7,1,5,8]
#bilancia = [4,3,3,1,9,8]

# scrivi qui
n = len(bilancia)
sum(bilancia[:n//2]) == sum(bilancia[n//2:])<jupyter_output><empty_output><jupyter_text>Moltiplicazione per listePer replicare gli elementi di una lista, è possibile usare l'operatore `*` che produce una NUOVA lista:<jupyter_code>[7,6,8] * 2
[7,6,8] * 3<jupyter_output><empty_output><jupyter_text>Notare che viene prodotta una NUOVA lista, e quella originale non viene modificata:<jupyter_code>la = [7,6,8]
lb = [7,6,8] * 3
la   # originale
lb   # risultato dell'espressione<jupyter_output><empty_output><jupyter_text>Possiamo moltiplicare una lista di stringhe:<jupyter_code>la = ["un", "mondo", "di", "parole"]
lb = la * 2
print(la)
print(lb)<jupyter_output>['un', 'mondo', 'di', 'parole', 'un', 'mondo', 'di', 'parole']<jupyter_text>Finchè moltiplichiamo liste che contengono elementi immutabili come numeri o stringhe, non si presentano particolari problemi:<jupyter_code>la = ["un", "mondo", "di", "parole"]
lb = la * 2

jupman.pytut()<jupyter_output><empty_output><jupyter_text>La questione diventa molto più complicata quando moltiplichiamo liste che contengono oggetti mutabili come altre liste. Vediamo un esempio:<jupyter_code>la = [5,6]
lb = [7,8,9]
lc = [la,lb] * 2
print(la)
print(lb)
print(lc)<jupyter_output>[[5, 6], [7, 8, 9], [5, 6], [7, 8, 9]]<jupyter_text>Stampando, vediamo che le liste `la` e `lb` si ripresentano all'interno di `lc` - ma esattamente, come? Le `print` possono ingannare sull'effettivo stato della memoria - per indagare meglio conviene usare Python Tutor:<jupyter_code>la = [5,6]
lb = [7,8,9]
lc = [la,lb] * 2

jupman.pytut()<jupyter_output><empty_output><jupyter_text>Arggh ! Vedrai apparire una giungla di frecce ! Questo perchè quando scriviamo `[la, lb]` creiamo una lista con due  _riferimenti_ alle liste `[5,6]` e `[7,8,9]`, e l'operatore `*` mentre duplica copia _i riferimenti_. Per il momento ci fermiamo qui, vedremo meglio le implicazioni in seguito nel tutorial [matrici - liste di liste](https://it.softpython.org/matrices-lists/matrices-lists-sol.html).  UguaglianzaPossiamo verificare se due liste sono uguali con l'operatore di uguaglianza `==`, che date due liste ritorna `True` se contengono elementi uguali oppure `False` altrimenti.<jupyter_code>[4,3,6] == [4,3,6]
[4,3,6] == [4,3]
[4,3,6] == [4,3,6, 'ciao']
[4,3,6] == [2,2,8]<jupyter_output><empty_output><jupyter_text>Possiamo verificare l'uguaglianza di liste con elementi eterogenei:<jupyter_code>['mele', 3, ['ciliegie', 2], 6] == ['mele', 3, ['ciliegie', 2], 6]
['banane', 3,['ciliegie', 2], 6] == ['mele', 3, ['ciliegie', 2], 6]<jupyter_output><empty_output><jupyter_text>Per verificare la disuguaglianza, possiamo usare l'operatore `!=`:<jupyter_code>[2,2,8] != [2,2,8]
[4,6,0] != [2,2,8]
[4,6,0] != [4,6,0,2]<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15882752557544758, 'fraction_numerical': 0.044737052429667516, 'mean_word_length': 4.264990532295393, 'pattern_counts': {'":': 0, '<': 305, '<?xml version=': 0, '>': 328, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 13, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '79', 'dir': 'jupyter-structured-clean-dedup', 'id': '402925', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 20701, 'n_tokens_neox': 20005, 'n_words': 5817, 'path': 'lists/lists2-sol.ipynb', 'repo_name': 'DavidLeoni/softpython-', 'size': '50078'}