Lezione 11: Set e operazioni insiemistiche ✅

In questa lezione scopri cosa sono i set in Python e come usarli per gestire collezioni senza duplicati. Imparerai a creare set, verificare la membership con in, applicare le principali operazioni insiemistiche (unione, intersezione, differenza, differenza simmetrica) e utilizzare metodi come add, update, remove, discard. Concludiamo con quando usare i set rispetto ad altre strutture, esercizi guidati, quiz e risorse.


🔗 Ripassi consigliati (interni):
• Variabili e Tipi di Dato → https://www.saperesemplice.com/variabili-tipi-dato-python/
• Operatori aritmetici, logici e di confronto → https://www.saperesemplice.com/operatori-python-aritmetici-logici-confronto/
• Ciclo while → https://www.saperesemplice.com/ciclo-while-python-base/


Dettagli lezione

⏱️ Tempo stimato: 35–45 minuti
🧩 Difficoltà: Facile
🎯 Obiettivi specifici

  • Creare e manipolare set e frozenset.
  • Eliminare duplicati e testare la membership in modo efficiente.
  • Applicare operazioni insiemistiche: unione (**), intersezione (**), differenza (**), differenza simmetrica (**).
  • Conoscere metodi e operatori: add, update, remove/discard, pop, clear, issubset/issuperset, isdisjoint, e versioni in‑place (|=, &=, -= , ^=).
  • Valutare quando usare i set rispetto a liste/tuple.

🧱 Che cos’è un set in Python

Un set è una collezione non ordinata di elementi unici (niente duplicati). È ideale quando ti servono elementi distinti e test di appartenenza rapidi.

# Creazione di set
empty = set()                 # ⚠️ {} crea un dict, non un set
colors = {"red", "green", "blue"}
nums = set([1, 2, 2, 3])      # → {1, 2, 3}

# Membership test
print("red" in colors)        # True
print("yellow" in colors)     # False

ℹ️ Gli elementi di un set devono essere hashable (immutabili). Puoi inserire numeri, stringhe, tuple (se i loro elementi sono immutabili), non liste o dict.

Domanda per te: perché {"a", (1,2)} è valido ma {[1,2], "a"} no?


🔧 Metodi principali dei set

s = {1, 3}
s.add(2)                   # {1, 2, 3}
s.update([3, 4, 5])        # aggiunge da iterabile → {1, 2, 3, 4, 5}

s.remove(5)                # rimuove 5; se non c'è → KeyError
s.discard(99)              # rimuove 99 se presente; altrimenti non fa nulla

x = s.pop()                # rimuove e ritorna *un* elemento arbitrario
s.clear()                  # svuota

💡 discard è sicuro quando non sei sicuro che l’elemento esista. remove lancia un errore se l’elemento non c’è.

Altri metodi utili
copy(), issubset() / issuperset(), isdisjoint().


∪ ∩ − ⊕ Operazioni insiemistiche

Operatori e metodi hanno equivalenti:

A = {1, 2, 3}
B = {3, 4, 5}

print(A | B)                  # unione        → {1, 2, 3, 4, 5}
print(A & B)                  # intersezione  → {3}
print(A - B)                  # differenza    → {1, 2}
print(A ^ B)                  # diff. simm.   → {1, 2, 4, 5}

print(A.union(B))
print(A.intersection(B))
print(A.difference(B))
print(A.symmetric_difference(B))

# Versioni in-place
A |= B   # A = A ∪ B
A &= B   # A = A ∩ B
A -= B   # A = A − B
A ^= B   # A = A ⊕ B

Relazioni tra insiemi:

C = {1, 2}
D = {1, 2, 3}
print(C <= D)           # subset (True)
print(C < D)            # subset *proprio* (True)
print(D >= C)           # superset (True)
print(C.isdisjoint({4,5}))  # True

✨ Suggerimento leggibilità: quando la formula è lunga, inserisci spazi attorno agli operatori insiemistici come sopra.


🧊 frozenset: set immutabile

Un frozenset è analogo a un set ma immutabile. È utile quando vuoi usare un set come chiave di un dizionario o elemento di un altro set.

f = frozenset({"read", "write"})
perms = {f, frozenset({"read"})}  # ok: elementi hashable
print(perms)

🧭 Quando usare i set (e quando no)

Usali quando:

  • ti servono elementi unici (deduplicazione rapida),
  • fai spesso test di appartenenza (x in s),
  • devi applicare algebra insiemistica tra collezioni (tag, permessi, utenti…).

Evita/attenzione quando:

  • ti serve un ordine stabile: i set sono non ordinati; se serve ordinare, usa sorted(s).
  • ti servono duplicati o conteggi → meglio una lista o collections.Counter.
  • vuoi memorizzare oggetti mutabili non hashable (liste, dict) → valuta tuple o frozenset di elementi immutabili.

⚠️ Errore comune da evitare
Pensare che set mantenga l’ordine di inserimento o consenta indicizzazione (s[0]). Non è così: usa sorted(s) per un elenco ordinato, oppure una lista se l’ordine conta.

Domanda per te: quale struttura useresti per contare quante volte un elemento compare? Perché un set non è adatto a questo compito?


🔶 Esempi pratici guidati

1) Deduplicare una lista di email

emails = ["[email protected]", "[email protected]", "[email protected]", "[email protected]"]
unique = set(emails)
print("Unique:", sorted(unique))   # ordina solo per stampa

2) Tag di articoli (unione/intersezione)

post_a = {"python", "beginner", "tips"}
post_b = {"python", "data", "tips"}
print("All tags:", post_a | post_b)             # union
print("Common tags:", post_a & post_b)          # intersection
print("Only A tags:", post_a - post_b)          # difference

3) Controlli di permessi con subset/superset

required = {"read", "write"}
user_perms = {"read", "write", "export"}
print(user_perms.issuperset(required))  # True → has all perms

4) Differenza simmetrica: A ⊕ B

A = {"apple", "banana", "fig"}
B = {"banana", "cherry"}
print("Exclusive items:", A ^ B)   # elements in exactly one set

💬 Domanda per il lettore: in un e‑commerce, come useresti intersection e difference per filtrare prodotti in base a caratteristiche presenti/assenti?


🧪 Curiosità (numeri, uguaglianza e hash)

Nei set (e nelle chiavi dei dict) due numeri che sono uguali per confronto (==) sono considerati lo stesso elemento. Esempio: 1 == 1.0 è True, quindi {1, 1.0} ha un solo elemento.

print({1, 1.0})     # {1.0} oppure {1} a seconda della rappresentazione

💡 Questo sorprende molti: è dovuto al fatto che confronto ed hash dei tipi numerici sono coerenti tra loro.


📖 Sezione teorica (riassunto visivo)

  • Set: collezione non ordinata senza duplicati; test di appartenenza rapido.
  • Operazioni: | (unione), & (intersezione), - (differenza), ^ (differenza simmetrica).
  • Metodi: add, update, remove/discard, pop, clear; relazioni issubset/issuperset, isdisjoint.
  • “: versione immutabile (hashable) per chiavi o set di set.
  • Quando usarli: deduplica, membership, algebra insiemistica; evita i set quando servono duplicati o ordine.

📚 Glossario tecnico

  • Deduplicazione: rimozione di elementi ripetuti da una collezione.
  • Differenza simmetrica: elementi presenti in esattamente uno dei due insiemi.
  • “: set immutabile e hashable.
  • Subset/Superset: sottoinsieme/sovrainsieme; operatori <=, <, >=, >.

📝 Esercizio finale

Dato un catalogo con tag multipli, scrivi uno script che:

  1. Deduplichi l’elenco dei tag globali.
  2. Dati due insiemi required e excluded, trovi i prodotti che contengono tutti i tag richiesti e non contengono tag esclusi (usa issuperset, isdisjoint o -).
  3. Stampa un rapporto in inglese con conteggio dei prodotti selezionati e i tag esclusivi tra required ed excluded (differenza simmetrica).

Schema d’aiuto (esempio dati):

products = [
    {"name": "Laptop A", "tags": {"ssd", "16gb", "light"}},
    {"name": "Laptop B", "tags": {"ssd", "32gb", "gaming"}},
    {"name": "Laptop C", "tags": {"hdd", "16gb"}},
]
required = {"ssd"}
excluded = {"gaming"}
# Your code here...

🧠 Quiz finale

Non guardare le risposte subito! Sono più sotto 👇

  1. Cosa garantisce un set in Python?
    A) Ordine stabile
    B) Niente duplicati
    C) Accesso per indice
  2. Qual è il modo corretto di creare un set vuoto?
    A) {}
    B) set()
    C) []
  3. Cosa fa A ^ B?
    A) Unione
    B) Intersezione
    C) Differenza simmetrica
  4. Cosa non puoi inserire in un set?
    A) ("a", 1)
    B) 3.14
    C) [1, 2]
  5. Qual è la differenza tra remove e discard?
    A) Nessuna
    B) remove lancia KeyError se l’elemento non c’è; discard no
    C) discard ordina il set
  6. Quale espressione verifica se X è sottoinsieme di Y?
    A) X >= Y
    B) X <= Y
    C) X | Y
  7. Perché {1, 1.0} ha dimensione 1?
    A) Perché i set ordinano gli elementi
    B) Perché 1 == 1.0 e condividono lo stesso hash
    C) Perché i float vengono scartati
  8. Quando non usare un set?
    A) Quando ti serve l’ordine o il conteggio delle ripetizioni
    B) Quando ti servono test di appartenenza rapidi
    C) Quando applichi unione/intersezione

❓ FAQ

1) I set mantengono l’ordine di inserimento?
No. Sono non ordinati. Se ti serve l’ordine, usa una lista o visualizza con sorted(s).

2) Posso avere un set di set?
Solo usando frozenset (hashable). Esempio: {frozenset({1,2}), frozenset({3})}.

3) Perché “ è veloce nella membership?
Perché usa tabelle hash; in media x in s è O(1), a costo di non avere ordine.

4) “ su un set rimuove l’ultimo elemento?
No: rimuove un elemento arbitrario (il set non ha ordine).

5) Come deduplico una lista preservando l’ordine?
Usa un approccio alternativo (es. dict.fromkeys(lista) o un ciclo con controllo seen). I set non preservano l’ordine originale.


Interni
• Variabili e Tipi di Dato → https://www.saperesemplice.com/variabili-tipi-dato-python/
• Operatori aritmetici/logici → https://www.saperesemplice.com/operatori-python-aritmetici-logici-confronto/
• Ciclo while (ripasso) → https://www.saperesemplice.com/ciclo-while-python-base/
• Percorso “Corsi Python – Programmare da zero” → https://www.saperesemplice.com/corsi-informatica/corsi-di-informatica-python/


🔁 Collegamento alla lezione successiva

➡️ Prosegui alla Lezione 12: Dizionari – dati associativi
(Il link verrà inserito non appena l’articolo sarà online.)


🗨️ Hai dubbi? Lascia un commento!
📩 Vuoi il PDF della lezione? Scrivici!
🔗 Condividi con un compagno di corso.


🧪 Risposte del quiz (mostra solo dopo aver provato)

  1. B
  2. B
  3. C
  4. C
  5. B
  6. B
  7. B
  8. A

📅 Aggiornato il 31/08/2025

Lascia un commento