📊 Introduzione alle Strutture Dati in Python
Le strutture dati sono fondamentali per organizzare, gestire e manipolare le informazioni. Scopri come usarle al meglio per programmare in modo ordinato ed efficiente.
🎯 Cosa Imparerai Oggi
Prima di iniziare con gli esercizi pratici, vediamo insieme quali sono le principali strutture dati e quando conviene usarle. Capirai come funzionano liste, dizionari e tuple, con esempi chiari e applicazioni reali.
🏗️ Le Basi delle Strutture Dati
In Python esistono tre modi principali per organizzare le informazioni: scopri quando usare ognuno di essi
Liste
Collezioni ordinate e modificabili
Ideali quando i dati cambiano nel tempo, con aggiunte, rimozioni e modifiche. Le liste sono la struttura più versatile e utilizzata in Python.
# ========== CREAZIONE E ACCESSO ==========
# Creazione lista
frutti = ["mela", "banana", "ciliegia"]
numeri = [1, 2, 3, 4, 5]
mista = ["testo", 42, 3.14, True]
# Accesso agli elementi (indice parte da 0)
print(frutti[0]) # Output: mela
print(frutti[1]) # Output: banana
print(frutti[-1]) # Output: ciliegia (ultimo elemento)
# Slicing (sotto-liste)
print(numeri[1:4]) # Output: [2, 3, 4]
print(numeri[:3]) # Output: [1, 2, 3]
print(numeri[2:]) # Output: [3, 4, 5]
# ========== MODIFICA LISTE ==========
# Aggiunta elementi
frutti.append("arancia") # Aggiunge alla fine
frutti.insert(1, "kiwi") # Inserisce in posizione 1
print(frutti) # ['mela', 'kiwi', 'banana', 'ciliegia', 'arancia']
# Modifica elemento
frutti[1] = "ananas"
print(frutti) # ['mela', 'ananas', 'banana', 'ciliegia', 'arancia']
# Rimozione elementi
frutti.remove("banana") # Rimuove per valore
eliminato = frutti.pop(2) # Rimuove per indice e restituisce valore
del frutti[0] # Rimuove per indice
print(frutti) # ['ananas', 'ciliegia']
# ========== OPERAZIONI UTILI ==========
# Lunghezza lista
print(len(frutti)) # Output: 2
# Controllo esistenza
if "mela" in frutti:
print("Mela presente!")
else:
print("Mela non trovata!")
# Concatenazione liste
lista1 = [1, 2, 3]
lista2 = [4, 5, 6]
combinata = lista1 + lista2
print(combinata) # [1, 2, 3, 4, 5, 6]
# Ripetizione
ripetuta = [0] * 5
print(ripetuta) # [0, 0, 0, 0, 0]
📌 Quando usare le Liste:
- Quando l’ordine degli elementi è importante
- Quando hai bisogno di modificare i dati frequentemente
- Per collezioni di elementi simili (numeri, nomi, ecc.)
- Quando devi mantenere elementi duplicati
Tuple
Collezioni ordinate ma immutabili
Perfette quando un dato deve rimanere invariato. Le tuple sono più veloci delle liste e garantiscono che i dati non vengano modificati accidentalmente.
# ========== CREAZIONE E ACCESSO ==========
# Creazione tupla (con parentesi tonde)
coordinate = (45.4642, 9.1900)
colori = ("rosso", "verde", "blu")
singola = (42,) # NOTA: la virgola è obbligatoria per tuple con un elemento
# Le parentesi sono opzionali in alcuni casi
coordinate_senza_parentesi = 45.4642, 9.1900
# Accesso agli elementi
print(coordinate[0]) # Output: 45.4642
print(coordinate[1]) # Output: 9.1900
print(colori[-1]) # Output: blu (ultimo elemento)
# Slicing funziona come per le liste
print(colori[1:]) # Output: ('verde', 'blu')
# ========== UNPACKING ==========
# Assegnazione multipla
x, y = coordinate
print(f"X: {x}, Y: {y}") # X: 45.4642, Y: 9.1900
# Tuple con dati misti
persona = ("Mario", 25, "Roma")
nome, eta, citta = persona
print(f"{nome} ha {eta} anni e vive a {citta}")
# Scambio variabili (trick utile)
a, b = 10, 20
a, b = b, a # Scambia i valori
print(f"a: {a}, b: {b}") # a: 20, b: 10
# ========== OPERAZIONI UTILI ==========
# Lunghezza tupla
print(len(colori)) # Output: 3
# Controllo esistenza
if "rosso" in colori:
print("Rosso presente!")
# Concatenazione tuple
tupla1 = (1, 2, 3)
tupla2 = (4, 5, 6)
combinata = tupla1 + tupla2
print(combinata) # (1, 2, 3, 4, 5, 6)
# Ripetizione
ripetuta = (0,) * 4
print(ripetuta) # (0, 0, 0, 0)
# ========== IMMUTABILITÀ ==========
# ATTENZIONE: Le tuple sono immutabili!
# coordinate[0] = 40.0 # ❌ Genera ERRORE: 'tuple' object does not support item assignment
# Ma puoi creare nuove tuple
nuove_coordinate = (40.0, coordinate[1])
print(nuove_coordinate) # (40.0, 9.1900)
📌 Quando usare le Tuple:
- Per dati che non devono mai cambiare (coordinate, date, configurazioni)
- Come chiavi nei dizionari (le liste non possono esserlo)
- Per migliorare le performance (sono più veloci delle liste)
- Per restituire valori multipli da funzioni
Dizionari
Strutture chiave → valore
Per modellare informazioni complesse in modo efficiente. I dizionari collegano chiavi univoche ai loro valori, permettendo accesso rapido ai dati.
# ========== CREAZIONE E ACCESSO ==========
# Creazione dizionario
studente = {
"nome": "Luca",
"età": 18,
"voto": 8.5,
"classe": "4A",
"materie": ["Matematica", "Italiano", "Inglese"]
}
# Accesso ai valori tramite chiave
print(studente["nome"]) # Output: Luca
print(studente["voto"]) # Output: 8.5
# Accesso sicuro con get()
print(studente.get("nome")) # Output: Luca
print(studente.get("indirizzo")) # Output: None (non genera errore)
print(studente.get("indirizzo", "Non specificato")) # Output: Non specificato
# ========== MODIFICA DIZIONARI ==========
# Aggiunta nuova chiave-valore
studente["città"] = "Milano"
studente["telefono"] = "123456789"
# Modifica valore esistente
studente["voto"] = 9.0
studente["età"] = 19
# Rimozione elementi
telefono = studente.pop("telefono") # Rimuove e restituisce il valore
del studente["città"] # Rimuove senza restituire
print(studente)
# ========== ITERAZIONE ==========
# Iterazione su chiavi
print("Chiavi:")
for chiave in studente.keys():
print(f"- {chiave}")
# Iterazione su valori
print("Valori:")
for valore in studente.values():
print(f"- {valore}")
# Iterazione su coppie chiave-valore
print("Coppie:")
for chiave, valore in studente.items():
print(f"{chiave}: {valore}")
# ========== OPERAZIONI UTILI ==========
# Verifica esistenza chiave
if "nome" in studente:
print(f"Lo studente si chiama {studente['nome']}")
# Lunghezza dizionario
print(f"Numero di proprietà: {len(studente)}")
# Unione dizionari
info_aggiuntive = {"hobby": "calcio", "sport": "nuoto"}
studente_aggiornato = {**studente, **info_aggiuntive}
# Copia dizionario (shallow copy)
copia_studente = studente.copy()
# ========== DIZIONARI COMPLESSI ==========
# Dizionari annidati
scuola = {
"studente1": {"nome": "Alice", "voto": 9},
"studente2": {"nome": "Bob", "voto": 7},
"studente3": {"nome": "Charlie", "voto": 8}
}
# Accesso a valori annidati
print(scuola["studente1"]["nome"]) # Output: Alice
📌 Quando usare i Dizionari:
- Per rappresentare oggetti con proprietà (utenti, prodotti, configurazioni)
- Quando serve accesso rapido ai dati tramite chiave
- Per contare occorrenze o raggruppare dati
- Per configurazioni e impostazioni
✍️ Esercitazioni Pratiche
Metti alla prova ciò che hai imparato con esercizi mirati
Modifica una Lista
Obiettivo: Aggiungi “arancia” alla lista e rimuovi “banana”.
frutti = ["mela", "banana", "ciliegia"]
# Aggiungi "arancia"
frutti.______("arancia")
# Rimuovi "banana"
frutti.______("banana")
print(frutti)
✅ Soluzione:
frutti = ["mela", "banana", "ciliegia"]
# Aggiungi "arancia"
frutti.append("arancia")
# Rimuovi "banana"
frutti.remove("banana")
print(frutti)
# Output: ['mela', 'ciliegia', 'arancia']
Dizionario Voti
Obiettivo: Crea un dizionario dei voti e calcola la media.
# Crea dizionario con voti
voti = {"Alice": 8, "Marco": 7, "Giulia": 9}
# Calcola la media
media = (______ + ______ + ______) / 3
print(f"Media voti: {media}")
✅ Soluzione:
# Metodo 1: Accesso diretto
media = (voti["Alice"] + voti["Marco"] + voti["Giulia"]) / 3
print(f"Media voti: {media}") # Media voti: 8.0
# Metodo 2: Con sum() e values() (più elegante)
media = sum(voti.values()) / len(voti)
print(f"Media voti: {media}") # Media voti: 8.0
Elemento Centrale
Obiettivo: Stampa l’elemento centrale della lista della spesa.
spesa = ["pane", "latte", "uova", "farina", "mele"]
# Stampa l'elemento centrale (terzo elemento)
print(___________)
# Output atteso: uova
✅ Soluzione:
# Metodo 1: Indice diretto
print(spesa[2])
# Indici: pane[0], latte[1], uova[2], farina[3], mele[4]
# Metodo 2: Calcolo automatico (funziona sempre)
indice_centrale = len(spesa) // 2
print(spesa[indice_centrale])
# // è la divisione intera (arrotonda verso il basso)
🔥 Sfida Finale: Rubrica Telefonica
Metti insieme liste, dizionari e cicli per creare un piccolo programma reale
🎯 Funzionalità richieste
- Memorizzare contatti (nome → telefono)
- Aggiungere nuovi contatti
- Cercare un contatto per nome
- Mostrare l’elenco completo
# Rubrica Telefonica
rubrica = {"Luca": "123456789", "Anna": "987654321"}
print("📱 Benvenuto nella Rubrica Telefonica!")
while True:
print("\n--- MENU ---")
scelta = input("Aggiungi (A), Cerca (C), Lista (L), Esci (E): ").upper()
if scelta == "A":
nome = input("Nome del contatto: ")
telefono = input("Numero di telefono: ")
rubrica[nome] = telefono
print(f"✅ {nome} aggiunto alla rubrica!")
elif scelta == "C":
nome = input("Cerca nome: ")
if nome in rubrica:
print(f"📞 {nome}: {rubrica[nome]}")
else:
print("❌ Contatto non trovato")
elif scelta == "L":
print("\n📋 Elenco completo:")
for nome, tel in rubrica.items():
print(f" 👤 {nome}: {tel}")
elif scelta == "E":
print("👋 Arrivederci!")
break
else:
print("⚠️ Scelta non valida")
💪 Bonus (opzionali)
- Salvataggio su file della rubrica (usa
json) - Eliminazione contatti (aggiungi opzione “D”)
- Modifica dei numeri esistenti (aggiungi opzione “M”)
- Validazione del numero di telefono (solo cifre)
📚 Riepilogo Rapido
📋 Liste
Ordinate, modificabili. Usa [] per crearle.
lista = [1, 2, 3]
🔒 Tuple
Ordinate, immutabili. Usa () per crearle.
tupla = (1, 2, 3)
🗂️ Dizionari
Chiave-valore. Usa {} per crearli.
diz = {"k": "v"}