# --- # jupyter: # jupytext: # formats: ipynb,py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.15.2 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- # %% [markdown] slideshow={"slide_type": "slide"} # # # Fondamenti di Programmazione # # # **Andrea Sterbini** # # lezione 6 - 12 ottobre 2023 # %% [markdown] # ## RECAP # - metodi dei contenitori **list, tuple, set, dict** # - 2 quesiti con la Susi # - assegnamenti multipli, packing ed unpacking # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Input e stampa # # Per prendere dei dati da tastiera si usa la funzione **input( [prompt] )** che: # - prende come argomento un "prompt" opzionale (un testo che viene mostrato per guidare l'utente) # - torna come risultato la stringa inserita, compresa di **'\\n'** finale # # **NOTA** torna sempre una stringa, se vi serve un tipo di dato diverso dovete convertirlo # %% editable=true slideshow={"slide_type": "subslide"} ## Esempio numero = input('Inserisci un intero tra 1 e 100') numero = int(numero) while numero < 0 or numero > 100: numero = input('Inserisci un intero tra 1 e 100') numero = int(numero) numero # %% [markdown] editable=true slideshow={"slide_type": ""} # # Come ordinare gli elementi di un contenitore # # - col metodo **sort** delle liste (modifica distruttiva) # - con la funzione **sorted(contenitore) -> list** # # L'ordinamento applicato è quello **crescente** naturale per il tipo di dato (crescente numerico per gli **int** e **float** oppure crescente alfabetico per le **str**) # %% editable=true slideshow={"slide_type": "subslide"} # Esempio L = [ 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette', 'otto', 'nove', 'dieci'] print(sorted(L)) L.sort() L # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # **NOTA** tutti gli elementi da ordinare devono essere **confrontabili** # - **OK** interi e float # - **OK** stringhe # - **NOT OK** interi e stringhe # %% editable=true slideshow={"slide_type": "fragment"} ## Otteniamo l'ordine OPPOSTO con l'argomento opzionale reverse=True print(sorted(L, reverse=True)) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ## Ordinamenti complessi # # Come fare per ordinarle in modo più sofisticato? # # Esempio: # **`[ 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette']`** : # - per **lunghezza crescente delle parole** # - e se sono di lunghezza uguale, **in ordine alfabetico** # # # # # # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # Potrei **trasformare ciascun elemento in una coppia**: # - lunghezza della parola # - parola # # e cercare di ordinare la nuova lista di coppie # %% slideshow={"slide_type": "fragment"} editable=true L = [ 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette'] # costruisco la lista di coppie L1 = [] for elemento in L: L1.append((len(elemento), elemento)) print(L1) # la ordino L1.sort() print(L1) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### FUNZIONA! MA PERCHE'? # Perchè per confrontare due coppie: # - prima confrontiamo il primo elemento (lunghezza della parole) # - poi solo in caso di parità passiamo a confrontare il secondo elemento # (ordine alfabetico delle parole) # # ... e questo era proprio quello che volevamo! # %% slideshow={"slide_type": "fragment"} editable=true # a questo punto basta estrarre dalle coppie solo la parola originale L2 = [] for lunghezza,elemento in L1: L2.append(elemento) L2 # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ## Ma se volessi che l'ordinamento fosse **STABILE** ? # Ovvero che elementi "uguali" che erano in un certo ordine relativo # # mantengano lo stesso ordine relativo # # **BASTA aggiungere alla tupla anche la posizione originale** # %% slideshow={"slide_type": "fragment"} editable=true ## Esempio L = [ 'uno', 'due', 'tre', 'sette', 'cinque', 'sei', 'sette'] # costruisco la lista di coppie L1 = [] # assieme all'elemento ne estraggo la posizione con enumerate for i,elemento in enumerate(L): # aggiungo la posizione *i* come ulteriore criterio da usare DOPO gli altri L1.append((len(elemento), elemento, i)) L1 # la ordino L1.sort() L1 # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Questo tipo di trasformazione di ciascun elemento si chiama trasformazione di Schwartz # # e può essere semplificata introducendo una piccola funzione che trasforma ciascun elemento # # da passare a **sorted** (che genera sempre un ordinamento stabile) # %% slideshow={"slide_type": "fragment"} editable=true # trasformazione di un solo elemento nella coppia corrispondente def trasforma_elemento(parola): return len(parola), parola # con la funzione *sorted* costruiamo una nuova lista ordinata # fornendo col parametro *key* la funzione di trasformazione sorted(L, key=trasforma_elemento) # NOTA: non c'è bisogno di mettere la posizione, visto che *sorted* è stabile (ci pensa lei) # %% [markdown] editable=true slideshow={"slide_type": ""} # ## Proviamo di nuovo, ma con un ordinamento più complicato # - in ordine **crescente** di lunghezza # - in caso di parità **alfabetico ignorando il case** # - in caso di parità **alfebetico** # %% editable=true slideshow={"slide_type": ""} def criterio_di_ordinamento(elemento): return ( len(elemento), # per prima cosa la lunghezza deve crescere elemento.lower(), # poi in ordine alfabetico CASELESS elemento ) # poi in ordine alfabetico L = [ 'PaPerino', 'plUTO', 'TopoLINO', 'minniE', 'PLUTO', 'papeRINO', 'papEROne', 'gasTONE', 'MInnie'] S = sorted(L, key=criterio_di_ordinamento, reverse=True) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ## Wooclap: secondo voi cosa stampa? # ![](wooclap.png) # %% editable=true slideshow={"slide_type": ""} print(S) # %% editable=true slideshow={"slide_type": ""} # Soluzione A = [ ''] # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # **MA INVECE** che definire una nuova funzione apposta (che magari ci serve solo in questa occasione) # # potrebbe essere comodo avere un modo per creare funzioni **USA e GETTA** # # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ## Funzioni anonime (espressioni *lambda*) # # Notate che la funzione precedente è estremamente semplice ed ha un solo compito: # - riceve dei parametri # - ritorna SOLO una espressione **SENZA ESEGUIRE ALTRE ISTRUZIONI** # # Quando calcolate **una sola espressione** potete scriverla senza usare la keyword **return** come # ```python # lambda argomenti: espressione # ``` # **NOTA** l'espressione può produrre una lista o una tupla di valori, che è proprio quello che ci serve per **sorted** # %% slideshow={"slide_type": "subslide"} editable=true # quindi la funzione *criterio_di_ordinamento* # può essere scritta direttamente come # criterio_di_ordinamento = lambda elemento: (len(elemento),elemento.lower(), elemento) print(criterio_di_ordinamento('PaPErino')) # S = sorted(L, key=lambda elemento: (len(elemento),elemento.lower(), elemento), reverse=True) print(S) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### RIASSUNTO # # Per ordinare un contenitore di elementi secondo criteri complessi: # - si definisce una funzione di trasformazione (o una lambda) che: # - riceve l'elemento da trasformare (**UN SOLO ARGOMENTO**) # - torna una tupla contenente nell'ordine i dati # che servono a rappresentare i criteri complessi # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # **Esempio:** ordiniamo la lista di parole # - in ordine **CRESCENTE** di lunghezza # - e in caso di parità in ordine alfabetico **DECRESCENTE** (Z->A) # # qui abbiamo un problema in più, **i due ordinamenti vanno in direzioni opposte!** # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # Uno dei due va rovesciato, perchè i confronti tra tuple sono sempre monodirezionali
# cioè tutti gli elementi delle tuple vengono confrontati nella stessa direzione # # **NON POSSO** rovesciare l'ordinamento alfabetico # # **POSSO** rovesciare l'ordinamento dei numeri **CAMBIANDOGLI SEGNO**! # %% slideshow={"slide_type": "fragment"} editable=true # definiamo la funzione di trasformazione adatta # NON possiamo rovesciare l'ordinamento alfabetico! # ALLORA rovesciamo l'ordinamento delle lunghezze def trasforma_elemento(el): return -len(el), el # lunghezza negativa: valori più grandi saranno più a sinistra # %% slideshow={"slide_type": "fragment"} editable=true print('disordinata', L) # vediamo cosa succede S = sorted(L, key=trasforma_elemento) # E' tutto a rovescio! print('ordinata', S) # %% slideshow={"slide_type": "fragment"} editable=true # cambiamo il parametro *reverse* per ordinare in direzione opposta S = sorted(L, key=trasforma_elemento, reverse=True) # ora va bene print(S) # %% slideshow={"slide_type": "fragment"} editable=true # A questo punto possiamo riscrivere la trasformazione # usando una funzione anonima con lambda # (notate le parentesi per creare la tupla) S = sorted(L, key=lambda el: (-len(el),el), reverse=True) print(S) # %% editable=true slideshow={"slide_type": ""} # Soluzione # Supponiamo di sapere età # e genere di alcuni personaggi L = [ (27, 'M', 'Paperino'), (31, 'M', 'Topolino'), (26, 'F', 'Paperina'), (32, 'F', 'Minnie')] def trasforma_elemento(terna): eta, genere, nome = terna return len(nome), genere, eta sorted(L, key=trasforma_elemento) # %% [markdown] slideshow={"slide_type": "slide"} editable=true # # List comprehension # ## una sintassi semplificata per costruire contenitori # # Spessissimo dobbiamo raccogliere in un contenitore più elementi e scriviamo roba del tipo di # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # - iniziamo costruendo una lista vuota # - iteriamo su un contenitore di elementi # - trasformiamo ciascun elemento # - lo aggiungiamo alla lista # - torniamo la lista ottenuta # # Sarebbe bello poter usare una sintassi più leggibile # # (che non ci obbliga a **simulare** il codice nella testa, simile alle espressioni insiemistiche) # %% slideshow={"slide_type": "fragment"} editable=true # dati dei valori lista_di_interi = [12, 34, 61, 2, 4, 7] # voglio costruire la lista dei cubi lista_di_cubi = [] # inizio con una lista vuota for x in lista_di_interi: # scandisco i valori lista_di_cubi.append(x**3) # aggiungo in fondo il cubo del valore corrente lista_di_cubi # %% [markdown] editable=true slideshow={"slide_type": ""} # ### List-comprehension: sintassi # ```python # [ espressione # valore calcolato per il risultato # for variabile in contenitore # per ciascun valore di contenitore di dati # ] # ``` # %% slideshow={"slide_type": "subslide"} editable=true lista_di_interi = [12, 34, 2, 61, 2, 4, 7] # Con la sintassi della list-comprehension lista_di_cubi = [ X**3 for X in lista_di_interi ] # - le parentesi indicano che tipo di contenitore stiamo costruendo (lista) # - il *for* indica su quale sequenza di dati stiamo iterando # - l'espressione all'inizio (X**3) indica come produciamo ogni nuovo valore lista_di_cubi # %% slideshow={"slide_type": "fragment"} editable=true # possiamo costruire altri tipi di contenitore # INSIEMI, racchiusi tra parentesi graffe { X**3 for X in lista_di_interi } # %% slideshow={"slide_type": "fragment"} editable=true # DIZIONARI che contengono coppie chiave:valore racchiuse tra parentesi graffe { X : X**3 for X in lista_di_interi } # %% slideshow={"slide_type": "fragment"} editable=true # TUPLE (qui ci vuole la parola tuple, non bastano le parentesi) tuple( X**3 for X in lista_di_interi ) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### e possiamo anche condizionare quali elementi trasformare e quali no # # ```python # [ espressione # valore calcolato # for variabile in contenitore # per ciascun valore di contenitore # if condizione # ma solo se la condizione è vera # ] # ``` # %% slideshow={"slide_type": "fragment"} editable=true # Voglio i cubi MA SOLO dei numeri dispari { x : x**3 for x in lista_di_interi if x%2!=0 } # %% [markdown] slideshow={"slide_type": "subslide"} # ### oppure costruire for nidificati # ```python # [ espressione # valore calcolato # for var1 in contenitore1 # per ciascun valore di contenitore1 # for var2 in contenitore2 # per ciascun valore di contenitore2 # ] # ``` # %% slideshow={"slide_type": "fragment"} editable=true # Esempio: costruisco l'insieme dei prodotti della tabellina del 10 S = { X*Y for X in range(1,11) for Y in range(1,11) } print(S) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### oppure costruire contenitori nidificati # ```python # [ [ espressione for var1 in contenitore1 ] # costruisco una lista # for var2 in contenitore2 ] # per ciascun valore del contenitore2 # ``` # %% slideshow={"slide_type": "fragment"} editable=true # Ad esempio la tabellina del 10 come lista di liste # (una lista per ogni riga) T = [ [ X*Y for X in range(1,11) ] # per ogni Y costruisco la riga con 10 moltiplicazioni for Y in range(1,11) ] # %pprint T # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # # Wooclap: Secondo voi cosa ottengo da questa list comprehension? # ![](wooclap.png) # %% slideshow={"slide_type": "subslide"} editable=true ## Vediamo la soluzione alfabeto = "abcdefghijk" parola = "bigia" [ alfabeto[alfabeto.index(X):] # il pezzo di alfabeto dalla X in poi for X in parola] # per ciascuna lettera X di parola # %% [markdown] slideshow={"slide_type": "slide"} # # INTERVALLO (RAI - anni 70) # %% slideshow={"slide_type": "fragment"} editable=true language="html" #