STRUTTURE DATI
a cura di Tommaso Bonetti
Introduzione
COSA SONO LE STRUTTURE DATI
Nella terza lezione hai imparato che le variabili sono degli elementi che rappresentano dati che possono variare nel tempo, dati di natura potenzialmente molto diversa tra di loro: per questo motivo le variabili possono essere di vario tipo, ad esempio int o float.
In base al problema da risolvere, però, potrebbe essere necessario utilizzare elementi diversi dalle semplici variabili: per questo motivo si utilizzano le cosiddette strutture dati.
Attenzione!
In questa lezione affronteremo solo due strutture dati, che riteniamo essere le uniche fondamentali per imparare le basi della programmazione in Python.
Se vuoi approfondire altre strutture per conto tuo, inizia dalle tuple (sono simili alle liste, che vedrai tra poco) e dai dizionari.
LE STRINGHE
In caso te lo stessi chiedendo, sì, abbiamo già affrontato le stringhe nella terza lezione. A quel punto del corso, però, avevi appena iniziato a scrivere le tue prime righe di Python e per semplicità le abbiamo definite come variabili, alla stregua di un int o un float.
La verità è che, a pensarci bene, una stringa non è altro che una sequenza di caratteri singoli. Una variabile può contenere un carattere singolo, per cui una stringa è di fatto una sequenza di variabili. Non preoccuparti, comunque: quello che hai imparato nella terza lezione è ancora vero, ma considerare le stringhe come strutture dati, anziché come variabili, ti consente di utilizzare qualche funzionalità aggiuntiva che ti tornerà molto utile.
Manipolazione
Come hai già visto, utilizzare una stringa è abbastanza semplice, ma ora vedrai qualche trucco che ti renderà la vita più facile.
Ad esempio, supponi di avere una stringa data = “02/07/2020” e di voler ottenere, a partire da data, un’altra stringa mese = “07”: per fare questo devi utilizzare un operatore che ti permetta di estrarre una substring, cioè una porzione della tua stringa di partenza.
L’operatore in questione sono le parentesi quadre []: al loro interno puoi specificare l’indice (la posizione nella stringa) del singolo carattere che vuoi estrarre. Se vuoi estrarre una stringa di più caratteri puoi specificare una coppia di indici, che indicano l’inizio e la fine della substring che ti interessa: l’indice iniziale indica il primo carattere incluso nella substring, quello finale indica il primo carattere escluso da essa.
Attenzione!
In informatica, gli indici di qualsiasi struttura dati partono da 0: questo significa che, data la stringa “ciao”, la lettera ‘c’ avrà indice 0, la ‘i’ avrà indice 1, la ‘a’ avrà indice 2 e così via.
In generale, quindi, gli indici di una stringa di n caratteri vanno da 0 a n-1.
Torniamo quindi all’esempio precedente. Se vuoi ottenere la stringa mese = “07”, l’istruzione da scrivere è
mese = data[3:5]. Questo perché il primo carattere della substring, lo ‘0’, è il quarto carattere (e avrà quindi indice 4-1 = 3) e il primo carattere escluso dalla substring è la seconda ‘/’, cioè il sesto carattere.
Adesso mettiti alla prova: nell'esempio sotto, crea una variabile contenente il tuo nome completo (nome e cognome), poi, usando l'operatore [], estrai la substring contenente solo il tuo nome, spazi esclusi.
1 nome_cognome = "Mario Rossi"
2
3 # Attenzione: gli indici da usare variano in base al tuo nome!
4 nome = nome_cognome[0:5]
5
6 print(nome)
Attenzione!
Se vuoi estrarre una substring il cui inizio coincide con l’inizio della stringa originale, ometti il primo indice: substring = str[:5].
Analogamente, ometti il secondo indice se vuoi che la substring finisca dove finisce la stringa originale: substring = str[2:].
Con questo operatore puoi anche utilizzare degli indici negativi: l’indice -1 si riferisce all’ultimo carattere della stringa, -2 al penultimo, -3 al terzultimo e così via. Questa funzione risulta utile quando non sei a conoscenza della lunghezza della stringa.
La prima cosa che hai imparato sulle stringhe è che, ogni volta che ne dichiari una, devi scriverla tra virgolette: serve per far capire a Python dove inizia e dove finisce la parola o frase in questione. Se però in una frase tu volessi utilizzare le virgolette, dovresti utilizzare il cosiddetto escape character \, un carattere aggiuntivo da anteporre alle virgolette interne, che fa capire a Python che quelle sono all’interno della stringa e non ne marcano la fine. L’utilizzo è il seguente: str = “La mia canzone preferita è \“Magic\” dei Coldplay”.
In precedenza hai anche imparato che puoi concatenare una stringa e una variabile (o un numero) con un’istruzione del tipo print(“Ho ” + str(20) + “ anni e ” + str(157) + “ giorni”), ma esiste un altro modo più semplice per ottenere lo stesso risultato senza neanche dover convertire la tua variabile in una stringa: l’operatore %s. Puoi utilizzare questo operatore nella posizione in cui vuoi inserire la variabile e poi specificare la variabile da sostituire, in questo modo: print(“Ho %s anni e %s giorni” % (20, 157)). Come vedi, puoi utilizzare questo operatore più volte in una singola stringa.
Ora che hai conosciuto questi due nuovi operatori, prova a utilizzarli in un programma. Qui sotto troverai una variabile film: assegnale una stringa contenente il titolo del tuo film preferito, poi usa l’operatore %s per inserire il contenuto di film nella stringa che viene visualizzata alla riga 3.
1 film = "The Imitation Game"
2
3 print("Ieri sera ho visto \"%s\" % (film))
Metodi dedicati
Ora che hai imparato come manipolare una stringa analizziamo due funzionalità importanti relative a questa struttura.
La funzione len() ti permette di ottenere la lunghezza di una stringa: per esempio, len(“Prova”) darà come risultato 5. A primo impatto potrebbe sembrare una cosa da poco, ma in futuro ti tornerà utile, per cui tienila bene a mente!
Un’altra funzionalità importante relativa alla manipolazione delle stringhe sono i metodi complementari upper() e lower(), che ti permettono di rendere la stringa, rispettivamente, tutta in maiuscolo o tutta in minuscolo. L’utilizzo è come segue: data una stringa str = “Test”, str.upper() restituisce “TEST” e str.lower() restituisce “test”.
Attenzione!
I metodi upper() e lower() non modificano direttamente la stringa ma una sua copia, quindi per trasformare effettivamente la tua stringa dovrai scrivere un'istruzione nella forma str = str.upper().
LE LISTE
Una lista è una struttura dati alla stregua di una stringa, con la quale ha alcune caratteristiche comuni. Una lista è anch’essa una sequenza di dati, con la differenza che, mentre una stringa è una sequenza di caratteri, una lista può contenere allo stesso tempo numeri, caratteri e addirittura stringhe o altre liste.
La lista condivide con la stringa anche alcuni operatori e funzionalità, come l’accesso agli elementi tramite l’operatore [] e la funzione len(), ma presenta anche molte altre caratteristiche che ora analizzeremo.
Dichiarazione e inizializzazione
La prima cosa da sapere per utilizzare una lista è come dichiararla e inizializzarla:
l’istruzione list = [1, 2, 3, “ciao”] dichiara una lista list e la inizializza, ma è anche possibile dichiarare una lista inizialmente vuota con list_empty = [].
Dichiarare una lista vuota può sembrare strano, ma è una funzionalità molto utile: infatti, contrariamente a quanto succede con le stringhe, è possibile aggiungere elementi e, in generale, manipolare una lista anche dopo la sua dichiarazione utilizzando alcuni metodi dedicati che vedrai tra poco.
Prova a mettere in pratica questi primi concetti che hai imparato: qui sotto, inizializza una lista valigia contenente tre oggetti che porti sempre in vacanza (ricorda, il nome di un oggetto è una stringa) e poi osserva l’output dell’istruzione print(valigia).
1 valigia = ["Occhiali da sole", "Maglietta", "Scarpe"]
2
3 print(valigia)
4
5 # soluzione esercizio successivo
6 valigia[1] = "Felpa"
7
8 print(valigia)
Accesso e modifica degli elementi
L’accesso agli elementi di una lista avviene esattamente nello stesso modo rispetto a una stringa, compresa la possibilità di selezionare una sottolista: first = list[0], oppure inizio = list[:2], o ancora
fine = list[3:].
L’unica differenza rispetto alle stringhe, in questo caso, è data dalla possibilità di modificare ogni singolo elemento di una lista: ad esempio, l’istruzione valigia[1] = “felpa” sostituisce all’elemento di indice 1 in valigia un nuovo elemento di valore “felpa”.
Adesso torna sul codice dell'esempio precedente con la valigia: supponi di aver cambiato idea riguardo a cosa portare e, dopo l’istruzione print(valigia) cambia il valore del secondo elemento della lista, poi visualizzala nuovamente per vedere il cambiamento. Ricorda: gli elementi si contano partendo da 0, per cui il secondo avrà indice 1.
Iterazione sulla lista
Uno dei motivi principali per utilizzare una lista in un programma è la possibilità di leggere o modificare i suoi elementi in sequenza e facilmente: per farlo userai un ciclo for, che hai incontrato nella scorsa lezione.
Esistono due modi per iterare sugli elementi di una lista (cioè farli scorrere uno a uno).
Il primo ti permette di visualizzare gli elementi della lista e di usarli all’interno di un’operazione o di un costrutto if-else, ma non di modificarli.
Data una lista valigia, la sintassi è for elem in valigia, seguita dalle operazioni da eseguire con gli elementi.
Il nome elem (che è totalmente arbitrario, puoi sceglierne uno a tuo piacimento) indica il singolo elemento della lista che viene preso in considerazione: puoi usarlo come vuoi per ottenere il valore dell’elemento considerato, ma non puoi tentare di assegnargli un valore (ad esempio elem = 5).
Il secondo metodo per iterare una lista, invece, ha una sintassi meno immediata ma non ha limitazioni riguardo alle istruzioni che puoi eseguire. Data una lista list la sintassi è for i in range(len(list)): la variabile i contiene l’indice dell’elemento desiderato, a cui puoi accedere tramite list[i].
Con questo metodo puoi tranquillamente modificare list[i]: infatti, mentre elem (vedi sopra) contiene solo il valore dell’elemento, list[i] è l’elemento stesso, che puoi manipolare come vuoi, modificando direttamente la lista.
Per esempio il comando valigia[i] = valigia[i].upper() sostituisce a ogni elemento il suo nome tutto in maiuscolo. Inoltre, con questo metodo puoi anche accedere a elementi con indice diverso da i (più avanti capirai perché questo è utile).
Prova ad esercitarti. Qui sotto trovi un programma che, data una lista di numeri interi, itera su di essa due volte: la prima volta si limita a visualizzare il quadrato di ogni elemento, mentre la seconda volta, oltre a visualizzare il quadrato, sostituisce a ogni numero il suo quadrato, e infine stampa la lista modificata.
Dopo aver osservato il suo funzionamento, modifica il programma (in particolare la riga 15) per far sì che ogni numero della lista venga sostituito dal triplo del numero stesso.
1 numeri = [1, 2, 3, 4, 5]
2
3 for n in numeri:
4 #al posto di n*n puoi anche utilizzare n**2
5 print(n*n)
6
7 print("\nLista dopo il primo ciclo for:")
8 print(numeri)
9 print("\n---\n")
10
11 for i in range(len(numeri)):
12 print(numeri[i] ** 2)
13
14 # sostituisco a ogni numero il suo triplo
15 numeri[i] = numeri[i] * 3
16
17 print("\nLista dopo il secondo ciclo for:")
18 print(numeri)
Metodi dedicati
Abbiamo detto in precedenza che è possibile aggiungere elementi a una lista: per fare ciò puoi scegliere tra due metodi dedicati che ora analizziamo.
Il primo metodo è append(valore): data la lista valigia, valigia.append(“jeans”) aggiungerà un elemento di valore “jeans” in fondo alla lista. Il valore del nuovo elemento, chiaramente, può anche essere il valore di una variabile: in tal caso, tra le parentesi scrivi semplicemente il nome della variabile.
Il secondo metodo è insert(indice, valore), che ti permette di scegliere la posizione in cui inserire il nuovo elemento: data la lista valigia, valigia.insert(2, “bermuda”) inserisce un elemento di valore “bermuda” all’indice 2, cioè al terzo posto.
Ricorda: l’indice che specifichi deve essere un numero intero, altrimenti il programma darà errore.
Un’altra operazione comune con le liste è la rimozione di un elemento e, anche in questo caso, puoi scegliere tra due metodi.
Il metodo list.remove(valore) (ad esempio valigia.remove(“bermuda”)) ti permette di specificare il valore dell’elemento da rimuovere, mentre list.pop(indice) (ad esempio valigia.pop(2)) ti permette di specificarne l’indice. L’utilizzo di un metodo o dell’altro dipende strettamente dal problema e dai dati a disposizione.
Qui sotto trovi una sandbox dove puoi prendere confidenza con le funzioni append, insert, remove e pop: segui le istruzioni nei commenti e sperimenta!
1 spesa = ["pane", "uova", "latte", "mele"]
2
3 # la lista sopra rappresenta una lista della spesa da rivedere
4 # ti è venuto in mente che hai finito lo shampoo: agiungilo dopo le uova
5 spesa.insert(2, "shampoo")
6
7 # hai cambiato idea sulla frutta: i mandarini sono più buoni delle mele!
8 # togli le mele dalla lista e al loro posto inserisci i mandarini
9 spesa.remove("mele")
10 spesa.append("mandarini")
11
12 # cos'è la prima cosa che avevi deciso di comprare? non ti serve più, eliminala
13 spesa.pop(0)
14
15 # ti è venuta sete: aggiungi alla lista la tua bibita preferita
16 spesa.append("Tè freddo")
17
18 # ecco la lista della spesa dopo averla sistemata!
19 print(spesa)
Come ultima cosa analizziamo altri due metodi estremamente utili che ti renderanno la vita molto più facile.
Il metodo list.index(valore) restituisce l’indice dell’elemento con il valore specificato (ad esempio valigia.index(“jeans”)): nel caso in cui ci fossero più elementi con quel valore, l’indice corrisponde al primo di questi elementi.
Ricorda: se non esiste alcun elemento con il valore specificato il programma darà errore, quindi accertati sempre di richiedere un valore esistente!
Il metodo list.sort() permette invece di ordinare la lista: funziona sia con i numeri (ordine crescente numerico) che con le stringhe (ordine crescente alfabetico).
Ricorda: sort() può essere utilizzato solo se tutti gli elementi della lista sono dello stesso tipo (ad esempio solo numeri o solo stringhe), altrimenti il programma darà errore!
Prova ora a utilizzare questi metodi. Nell'esempio sotto è stata inizializzata una lista vocabolario: utilizza i metodi index() e sort() per svolgere le task scritte nei commenti!
1 vocabolario = ["becco", "albero", "sorpasso", "alieno", "libro"]
2
3 # verifica che la funzione sort() funzioni nel modo corretto:
4 # per prima cosa, visualizza l'indice di "alieno"
5 print(str(vocabolario.index("alieno")))
6
7 # adesso ordina vocabolario, poi visualizza nuovamente l'indice di "alieno"
8 vocabolario.sort()
9 print(str(vocabolario.index("alieno")))
10
11 # e per finire visualizza vocabolario: ora è tutto in ordine!
12 print(vocabolario)
CONCLUSIONE
Complimenti, hai completato la lezione 5!
In questa lezione hai imparato a riconoscere due importanti strutture dati, le stringhe e le liste,
e hai visto come manipolarle e quali sono le funzioni a loro dedicate.
Usa i pulsanti qui sotto per avanzare alla prossima lezione o per tornare alla home del corso.