Questa guida presenta esercizi pratici, con difficoltà crescente, per imparare a verificare la presenza di chiavi, cercare per valore e utilizzare dictionary e list comprehension per ricerche più avanzate. Verrà inoltre introdotta la fuzzy matching per la gestione di input imprecisi. Impara a sfruttare al meglio i dizionari Python per una gestione efficiente dei tuoi dati.
👉Strutture Dati Python: Confronto e Uso di Set, List, Dict
Esercizio 1 (Facile): Verifica Presenza Chiave
Scenario:
Sei un bibliotecario e vuoi verificare rapidamente se un libro con un dato codice identificativo è presente nel catalogo della biblioteca, che è rappresentato come un dizionario dove le chiavi sono i codici dei libri e i valori sono i titoli.
# Catalogo: {codice_libro: titolo}
catalogo = {
"A123": "Il Signore degli Anelli",
"B456": "Harry Potter",
"C789": "1984",
"D012": "Il Piccolo Principe"
}
# Chiedi all'utente di inserire il codice del libro da cercare
codice = input("Inserisci il codice del libro da cercare: ")
# --- Soluzione 1: Usare l'operatore 'in' ---
print("\n--- Verifica con 'in' ---")
if codice in catalogo:
# Se il codice è una chiave nel dizionario, accedi al suo valore
print(f"Libro trovato: {catalogo[codice]}")
else:
print("Libro non presente nel catalogo.")
# --- Soluzione 2: Usare il metodo .get() ---
print("\n--- Verifica con .get() ---")
# .get(chiave, valore_di_default) cerca la chiave.
# Se la trova, restituisce il valore associato.
# Se NON la trova, restituisce il valore specificato come secondo argomento (valore_di_default).
risultato = catalogo.get(codice, "Libro non presente nel catalogo.")
# Se .get() ha trovato la chiave, 'risultato' sarà il titolo.
# Altrimenti, 'risultato' sarà la stringa "Libro non presente nel catalogo.".
if risultato != "Libro non presente nel catalogo.":
# Per mostrare il titolo solo se trovato usando .get()
print(f"Libro trovato (con .get()): {risultato}")
else:
print(risultato)
Spiegazione:
- L’operatore
inè il modo più diretto e leggibile per verificare se una chiave esiste nel dizionario. RestituisceTruese la chiave è presente,Falsealtrimenti. È ideale per controlli booleani. - Il metodo
.get(key, default)è utile quando vuoi ottenere il valore associato a una chiave, ma vuoi evitare un errore (KeyError) nel caso in cui la chiave non esista. Fornisce un valore di default da restituire in quel caso. Se il secondo argomento (il valore di default) viene omesso e la chiave non è trovata,.get()restituisceNone. - La sintassi
catalogo[codice](accesso diretto con parentesi quadre) funziona solo se sei certo che la chiavecodiceesista nel dizionario. Se la chiave non esiste, questa operazione solleva un erroreKeyErrore il tuo programma si interrompe. Per questo motivo, è spesso usata dopo aver verificato la presenza della chiave conin, o quando si lavora in contesti dove la chiave è garantita esistere.
Esercizio 2 (Facile): Ricerca per Valore
Scenario:
Invece di cercare un libro per il suo codice, ora hai il titolo del libro e vuoi trovare il codice identificativo corrispondente nel catalogo della biblioteca.
# Catalogo: {codice_libro: titolo}
catalogo = {
"A123": "Il Signore degli Anelli",
"B456": "1984",
"C789": "Harry Potter",
"D012": "1984" # Notare un titolo duplicato per dimostrazione
}
titolo_cercato = input("Inserisci il titolo del libro da cercare: ")
codice_trovato = None # Variabile per memorizzare il codice trovato
# --- Scansiona tutte le coppie chiave-valore ---
# .items() restituisce una "vista" degli elementi del dizionario come coppie (chiave, valore)
for codice, titolo in catalogo.items():
# Controlla se il valore (titolo) della coppia corrente corrisponde al titolo cercato
if titolo == titolo_cercato:
# Se trovi una corrispondenza, stampa il codice associato
print(f"Trovato codice: {codice} per il titolo '{titolo_cercato}'")
# break # Se vuoi trovare solo la prima corrispondenza, decommenta questa riga
# Dopo il ciclo, puoi verificare se è stata trovata almeno una corrispondenza
# (se non hai usato break e vuoi sapere se esiste A PRESCINDERE dalla stampa)
# Una ricerca per valore può trovare più chiavi se i valori non sono unici.
# Per sapere se ALMENO una corrispondenza esiste:
if titolo_cercato in catalogo.values(): # .values() restituisce una vista dei soli valori
print(f"Il titolo '{titolo_cercato}' è presente nel catalogo (potrebbero esserci più codici associati).")
else:
print(f"Il titolo '{titolo_cercato}' non è presente nel catalogo.")
Output:
Inserisci il titolo del libro da cercare: Il Signore degli Anelli
Trovato codice: A123 per il titolo ‘Il Signore degli Anelli’
Il titolo ‘Il Signore degli Anelli’ è presente nel catalogo (potrebbero esserci più codici associati).
Spiegazione:
- Il metodo
.items()è essenziale per iterare su un dizionario ottenendo sia la chiave che il valore per ogni elemento sotto forma di una tupla(chiave, valore). - Un ciclo
forviene utilizzato per esaminare ciascuna coppia. All’interno del ciclo, si confronta iltitolocorrente con iltitolo_cercato. - Una ricerca per valore è intrinsecamente meno efficiente di una ricerca per chiave, specialmente in dizionari molto grandi, poiché richiede di scorrere tutti (o molti) gli elementi del dizionario. La ricerca per chiave in un dizionario Python è in media O(1) (tempo costante), mentre la ricerca per valore è O(n) (tempo lineare, dove n è il numero di elementi).
- Se i valori nel tuo dizionario non sono unici (come nell’esempio con “1984” associato a due codici), una ricerca per valore potrebbe trovare più corrispondenze. Il codice d’esempio stampa tutte le corrispondenze trovate a meno che non venga usato
break. - Il metodo
.values()restituisce una vista di tutti i valori nel dizionario. Puoi usarlo con l’operatoreinper verificare se un valore specifico esiste nel dizionario, ma non ti dà direttamente la chiave o le chiavi associate.
Esercizio 3 (Intermedio): Ricerca con Condizioni Multiple (Comprensioni)
Scenario:
Gestisci un inventario di diversi prodotti, dove per ciascun prodotto è memorizzata la quantità in stock e il prezzo unitario (rappresentato come un dizionario di dizionari). Hai bisogno di identificare rapidamente tutti i prodotti le cui scorte sono al di sotto di una certa soglia (es. quantità minore di 10) per pianificare un riordino.
# Inventario: {nome_prodotto: {dettagli}}
inventario = {
"mouse": {"quantità": 15, "prezzo": 20, "categoria": "Elettronica"},
"tastiera": {"quantità": 5, "prezzo": 50, "categoria": "Elettronica"},
"monitor": {"quantità": 8, "prezzo": 200, "categoria": "Elettronica"},
"mela": {"quantità": 30, "prezzo": 1, "categoria": "Alimentari"},
"pane": {"quantità": 7, "prezzo": 2, "categoria": "Alimentari"}
}
# Definire la soglia di scorta bassa
soglia_quantita = 10
# --- Ricerca prodotti con quantità < soglia usando una dictionary comprehension ---
# Una dictionary comprehension permette di creare un nuovo dizionario
# filtrando o trasformando gli elementi di un altro iterabile.
scorte_basse = {
nome: dati # Coppia chiave: valore da includere nel nuovo dizionario
for nome, dati in inventario.items() # Iterazione sugli elementi dell'inventario
if dati["quantità"] < soglia_quantita # Condizione di filtro
}
# Stampa il nuovo dizionario contenente solo i prodotti con scorte basse
print("Prodotti con scorte basse:")
print(scorte_basse)
# --- Esempio di ricerca con condizioni multiple aggiuntive ---
# Cerchiamo prodotti con quantità < soglia E che siano di categoria "Elettronica"
scorte_basse_elettronica = {
nome: dati
for nome, dati in inventario.items()
if dati["quantità"] < soglia_quantita and dati["categoria"] == "Elettronica"
}
print("\nProdotti di Elettronica con scorte basse:")
print(scorte_basse_elettronica)
Output:
Prodotti con scorte basse:
{‘tastiera’: {‘quantità’: 5, ‘prezzo’: 50, ‘categoria’: ‘Elettronica’}, ‘monitor’: {‘quantità’: 8, ‘prezzo’: 200, ‘categoria’: ‘Elettronica’}, ‘pane’: {‘quantità’: 7, ‘prezzo’: 2, ‘categoria’: ‘Alimentari’}}
Prodotti di Elettronica con scorte basse:
{‘tastiera’: {‘quantità’: 5, ‘prezzo’: 50, ‘categoria’: ‘Elettronica’}, ‘monitor’: {‘quantità’: 8, ‘prezzo’: 200, ‘categoria’: ‘Elettronica’}}
Spiegazione:
- La Dictionary Comprehension
{nuova_chiave: nuovo_valore for elemento in iterabile if condizione}è una sintassi concisa e potente per creare dizionari basati su dizionari esistenti (o altri iterabili), applicando opzionalmente trasformazioni e filtri. inventario.items()viene utilizzato per iterare su ciascuna coppia(nome, dati)nel dizionarioinventario.- La parte
if dati["quantità"] < soglia_quantitaè la condizione di filtro. Solo le coppie per cui questa condizione è vera vengono incluse nel nuovo dizionarioscorte_basse. dati, in questo caso, è il sotto-dizionario (es.{"quantità": 15, "prezzo": 20}). Per accedere alla quantità, si usadati["quantità"].- Le comprensioni supportano condizioni multiple usando operatori logici come
andeor, rendendole molto flessibili per ricerche basate su criteri complessi.
Esercizio 4 (Intermedio): Ricerca Annidata (Comprensioni di Lista)
Scenario:
Sei responsabile del registro esami di un’università, rappresentato come un dizionario dove le chiavi sono i nomi degli studenti e i valori sono liste di esami sostenuti. Devi trovare i nomi di tutti gli studenti che hanno superato un esame specifico.
# Registro: {nome_studente: [lista_esami_sostenuti]}
registro = {
"Alice": ["Matematica", "Fisica", "Programmazione"],
"Bob": ["Fisica", "Chimica"],
"Charlie": ["Matematica", "Storia"],
"David": ["Chimica"]
}
esame_cercato = input("Inserisci il nome dell'esame da cercare: ")
# --- Trova gli studenti che hanno sostenuto l'esame usando una list comprehension ---
# Una list comprehension [nuovo_elemento for elemento in iterabile if condizione]
# crea una nuova lista filtrando o trasformando gli elementi.
studenti_trovati = [
nome # Elemento da includere nella nuova lista (il nome dello studente)
for nome, esami_sostenuti in registro.items() # Iterazione sugli elementi del registro
if esame_cercato in esami_sostenuti # Condizione di filtro (l'esame è nella lista esami_sostenuti)
]
# Stampa la lista degli studenti trovati
print(f"\nStudenti che hanno sostenuto l'esame '{esame_cercato}':")
print(studenti_trovati)
Output:
Inserisci il nome dell’esame da cercare: Fisica
Studenti che hanno sostenuto l’esame ‘Fisica’:
[‘Alice’, ‘Bob’]
Spiegazione:
- Questa volta usiamo una List Comprehension
[nuovo_elemento for elemento in iterabile if condizione]perché l’output desiderato è una lista (i nomi degli studenti), non un dizionario. - Ancora una volta,
registro.items()itera sulle coppie(nome, esami_sostenuti). - La parte
if esame_cercato in esami_sostenutiè la condizione di filtro. Verifica se la stringaesame_cercatoè presente nella listaesami_sostenutiassociata allo studente corrente. - Le comprensioni (di lista o dizionario) sono particolarmente utili per la ricerca e il filtraggio quando i dati sono strutturati in liste o dizionari annidati, offrendo una sintassi più leggibile e spesso più efficiente rispetto ai cicli
forespliciti con append o creazione di nuovi dizionari.
Esercizio 5 (Avanzato): Ricerca con Dizionari Annidati (Iterazione Multi-Livello)
Scenario:
Stai gestendo un database aziendale strutturato come un dizionario di dizionari. Il livello superiore rappresenta i dipartimenti, e ogni dipartimento è un dizionario dove le chiavi sono gli ID dei dipendenti e i valori sono sotto-dizionari con i dettagli del dipendente (nome, ruolo, ecc.). Dato l’ID di un dipendente, devi trovare in quale dipartimento lavora e recuperare i suoi dettagli.
# Database Dipendenti: {dipartimento: {id_dipendente: {dettagli}}}
dipendenti = {
"IT": {
"001": {"nome": "Mario Rossi", "ruolo": "Sviluppatore Senior", "progetto": "Alpha"},
"002": {"nome": "Luigi Bianchi", "ruolo": "Analista IT", "progetto": "Beta"}
},
"Vendite": {
"003": {"nome": "Anna Verdi", "ruolo": "Manager Vendite", "regione": "Nord"},
"004": {"nome": "Paolo Neri", "ruolo": "Commerciale", "regione": "Sud"}
},
"Marketing": {
"005": {"nome": "Giulia Marroni", "ruolo": "Specialista Marketing", "campagna": "Estiva"}
}
}
id_ricerca = input("Inserisci l'ID del dipendente da cercare: ")
dipendente_trovato = False # Flag per sapere se abbiamo trovato il dipendente
# --- Ricerca iterando sui livelli del dizionario annidato ---
# Itera sul dizionario più esterno (i dipartimenti)
for nome_dipartimento, impiegati_nel_dipartimento in dipendenti.items():
# impiegati_nel_dipartimento è il sotto-dizionario {id_dipendente: {dettagli}} per quel dipartimento
# Controlla se l'id_ricerca è una chiave nel sotto-dizionario del dipartimento corrente
if id_ricerca in impiegati_nel_dipartimento:
# Se trovato, stampa le informazioni
print(f"\nDipendente trovato!")
print(f"Dipartimento: {nome_dipartimento}")
print(f"Dettagli: {impiegati_nel_dipartimento[id_ricerca]}")
dipendente_trovato = True # Imposta il flag
break # Interrompi il ciclo una volta trovato il dipendente
# Controlla il flag dopo il ciclo per stampare un messaggio se non trovato
if not dipendente_trovato:
print(f"\nDipendente con ID {id_ricerca} non trovato nel database.")
Output:
Inserisci l’ID del dipendente da cercare: 004
Dipendente trovato!
Dipartimento: Vendite
Dettagli: {‘nome’: ‘Paolo Neri’, ‘ruolo’: ‘Commerciale’, ‘regione’: ‘Sud’}
Spiegazione:
- Questo esercizio richiede di iterare attraverso più livelli di annidamento del dizionario. Il ciclo
for nome_dipartimento, impiegati_nel_dipartimento in dipendenti.items():itera sul primo livello (i dipartimenti). - Dentro il ciclo,
impiegati_nel_dipartimentoè il dizionario che rappresenta tutti gli impiegati in quel dipartimento. Possiamo quindi usare l’operatoreinper verificare seid_ricercaè una chiave in questo sotto-dizionario:if id_ricerca in impiegati_nel_dipartimento:. - Se la condizione è vera, significa che l’impiegato con l’ID cercato si trova in questo dipartimento. Possiamo quindi accedere ai suoi dettagli usando
impiegati_nel_dipartimento[id_ricerca]. - L’uso di un flag (
dipendente_trovato) o la clausolaelsenel ciclofor(come mostrato nell’input utente originale, che si esegue solo se il ciclo termina senza incontrare unbreak) permette di gestire il caso in cui l’elemento cercato non venga trovato dopo aver controllato tutti i dipartimenti.
Esercizio 6 (Avanzato): Ricerca con Fuzzy Matching (Corrispondenza Approssimata)
Scenario:
Stai creando un semplice sistema di ricerca per un catalogo di prodotti in un e-commerce (rappresentato da un dizionario {nome_prodotto: prezzo}). Gli utenti potrebbero commettere piccoli errori di battitura durante la digitazione del nome del prodotto. Devi implementare una ricerca che tolleri questi errori e trovi il prodotto con il nome più simile a quello digitato dall’utente.
# Necessario installare la libreria difflib se non è già presente (è standard in Python, ma è bene saperlo)
# pip install difflib
from difflib import get_close_matches
# Catalogo Prodotti: {nome_prodotto: prezzo}
prodotti = {
"iphone": 999,
"macbook": 1499,
"airpods": 199,
"ipad": 799,
"apple watch": 399,
"homepod": 299
}
query = input("Cerca prodotto (puoi fare errori di battitura): ").lower() # Converti in minuscolo per ricerca case-insensitive
# --- Trova corrispondenze approssimate usando get_close_matches ---
# get_close_matches(parola_da_cercare, lista_di_candidati, n=numero_risultati, cutoff=soglia_similarità)
# cerca parole nella lista_di_candidati che sono "vicine" a parola_da_cercare.
matches = get_close_matches(query, prodotti.keys(), n=1, cutoff=0.6)
# Controlla se sono state trovate corrispondenze (la lista 'matches' non è vuota)
if matches:
# get_close_matches restituisce una lista delle migliori corrispondenze.
# Prendiamo la prima (la migliore, dato che n=1).
prodotto_trovato_key = matches[0]
# Recupera il prezzo dal dizionario usando la chiave trovata
prezzo_prodotto = prodotti[prodotto_trovato_key]
print(f"\nRisultato trovato:")
print(f"Prodotto più simile: {prodotto_trovato_key}")
print(f"Prezzo: €{prezzo_prodotto}")
else:
print(f"\nNessun risultato trovato per '{query}' (o la corrispondenza è troppo bassa).")
Output:
Cerca prodotto (puoi fare errori di battitura): ipad
Risultato trovato:
Prodotto più simile: ipad
Prezzo: €799
Spiegazione:
- Questo esercizio va oltre la ricerca esatta e introduce il concetto di fuzzy matching (corrispondenza approssimata), utile quando i dati di input potrebbero contenere errori o variazioni.
- Il modulo standard
difflibdi Python, in particolare la funzioneget_close_matches(), è progettato per questo scopo. get_close_matches(query, prodotti.keys(), n=1, cutoff=0.6)cerca nel dizionarioprodottile chiavi che sono simili alla stringaquerydigitata dall’utente.query: La stringa da confrontare.prodotti.keys(): La lista di stringhe in cui cercare (le chiavi del dizionario).n=1: Chiediamo di restituire solo la migliore corrispondenza trovata.cutoff=0.6: Questo è un valore tra 0.0 e 1.0 che imposta una soglia di “qualità” della corrispondenza. Solo le corrispondenze con un punteggio di somiglianza superiore a 0.6 (in questo caso) vengono considerate valide. Aumentando il cutoff, si richiedono corrispondenze più precise.
get_close_matches()restituisce una lista (potenzialmente vuota) delle corrispondenze trovate, ordinate per similarità (la migliore per prima). Controlliamo se la listamatchesnon è vuota per sapere se è stata trovata almeno una corrispondenza valida.- Convertire l’input dell’utente (
query.lower()) e confrontarlo con le chiavi del dizionario anch’esse trattate in modo case-insensitive (se necessario) garantisce che la ricerca non sia sensibile alle maiuscole/minuscole.
Ogni esercizio affronta un problema pratico, introducendo gradualmente concetti più complessi come comprensioni, strutture annidate, iterazione multi-livello e fuzzy matching, mostrando la versatilità dei dizionari e delle tecniche di ricerca in Python.




