CodeGym /Corsi /JAVA 25 SELF /Operazioni di unione, intersezione e differenza

Operazioni di unione, intersezione e differenza

JAVA 25 SELF
Livello 32, Lezione 2
Disponibile

1. Operazione union (unione degli insiemi)

In Java, per rappresentare gli insiemi si usa l’interfaccia Set<T>. A differenza delle liste (List), gli insiemi garantiscono l’unicità degli elementi e, di norma, non si preoccupano dell’ordine (a meno di usare implementazioni specifiche, per esempio LinkedHashSet). Le implementazioni più diffuse — HashSet e TreeSet. Il loro compito principale — determinare rapidamente la presenza di un elemento e garantire l’assenza di duplicati.

Quando servono gli insiemi?

  • Quando è importante l’unicità: ad esempio, l’elenco di tutti gli utenti unici che hanno visitato il sito.
  • Quando serve verificare rapidamente la presenza di un elemento: il metodo contains di HashSet in genere funziona in tempo costante.
  • Quando bisogna eseguire operazioni tipiche sugli insiemi: unione, intersezione, differenza.

Union è l’unione di due o più insiemi: il risultato contiene tutti gli elementi di entrambi gli insiemi di partenza (senza ripetizioni).

Esempio pratico

Supponiamo di avere due insiemi di studenti che frequentano i club «Robotica» e «Programmazione»:

Set<String> robotics = Set.of("Anya", "Boris", "Vika");
Set<String> programming = Set.of("Vika", "Gleb", "Dasha");

Dobbiamo ottenere l’insieme di tutti gli studenti che frequentano almeno un club.

Soluzione con la Stream API

Il modo più diretto è concatenare i due stream e raccoglierli in un Set:

Set<String> all = Stream.concat(
        robotics.stream(),
        programming.stream()
    ).collect(Collectors.toSet());

System.out.println(all); // [Anya, Boris, Vika, Gleb, Dasha]

Spiegazione:

  • Stream.concat concatena due stream.
  • collect(Collectors.toSet()) raccoglie gli elementi in un insieme (eliminando automaticamente i duplicati).

Alternativa: più di due insiemi

Se abbiamo tre o più club, usiamo Stream.of e flatMap:

Set<String> math = Set.of("Zhenya", "Vika", "Boris");

Set<String> all = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

System.out.println(all); // [Anya, Boris, Vika, Gleb, Dasha, Zhenya]

Perché proprio Set?
Perché Set elimina automaticamente i duplicati. Se si raccoglie in una List, gli stessi nomi compariranno più volte.

2. Operazione intersection (intersezione degli insiemi)

Intersection sono gli elementi presenti contemporaneamente in entrambi gli insiemi.

Esempio pratico

Trovare gli studenti che frequentano sia «Robotica» sia «Programmazione»:

Set<String> robotics = Set.of("Anya", "Boris", "Vika");
Set<String> programming = Set.of("Vika", "Gleb", "Dasha");

Soluzione con la Stream API:

Set<String> both = robotics.stream()
    .filter(programming::contains)
    .collect(Collectors.toSet());

System.out.println(both); // [Vika]

Spiegazione:
Passiamo su tutti i partecipanti a «Robotica» e filtriamo solo quelli che sono in «Programmazione». Il risultato è l’insieme dei nomi presenti in entrambi i club.

Metodo alternativo (senza Stream API)

Si può usare il metodo incorporato retainAll (modifica l’insieme corrente):

Set<String> intersection = new HashSet<>(robotics);
intersection.retainAll(programming);
System.out.println(intersection); // [Vika]

Ma nell’ambito della Stream API poniamo l’accento sugli stream.

3. Operazione difference (differenza tra insiemi)

Difference sono gli elementi del primo insieme che non sono presenti nel secondo.

Esempio pratico

Trovare gli studenti che frequentano solo «Robotica» e non «Programmazione»:

Set<String> robotics = Set.of("Anya", "Boris", "Vika");
Set<String> programming = Set.of("Vika", "Gleb", "Dasha");

Soluzione con la Stream API:

Set<String> onlyRobotics = robotics.stream()
    .filter(name -> !programming.contains(name))
    .collect(Collectors.toSet());

System.out.println(onlyRobotics); // [Anya, Boris]

Spiegazione:
Filtriamo i partecipanti a «Robotica», lasciando solo quelli che non sono in «Programmazione».

Metodo alternativo (senza Stream API)

Set<String> difference = new HashSet<>(robotics);
difference.removeAll(programming);
System.out.println(difference); // [Anya, Boris]

4. Esercizi pratici: elaborazione di elenchi di utenti

Esercizio 1: trovare gli studenti che frequentano un solo club

Bisogna scoprire chi frequenta solo «Robotica» oppure solo «Programmazione», ma non entrambi. Questa è la differenza simmetrica (xor per insiemi):

Set<String> onlyOne = Stream.concat(
        robotics.stream().filter(name -> !programming.contains(name)),
        programming.stream().filter(name -> !robotics.contains(name))
    ).collect(Collectors.toSet());

System.out.println(onlyOne); // [Anya, Boris, Gleb, Dasha]

Esercizio 2: elenco di tutti gli studenti unici provenienti da più club

Set<String> all = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

System.out.println(all); // [Anya, Boris, Vika, Gleb, Dasha, Zhenya]

Esercizio 3: trovare gli studenti che non frequentano alcun club

Supponiamo di avere l’elenco di tutti gli alunni della classe:

Set<String> allStudents = Set.of("Anya", "Boris", "Vika", "Gleb", "Dasha", "Zhenya", "Igor’", "Katya");

Bisogna individuare chi non frequenta alcun club:

Set<String> attendees = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

Set<String> notInAny = allStudents.stream()
    .filter(name -> !attendees.contains(name))
    .collect(Collectors.toSet());

System.out.println(notInAny); // [Igor’, Katya]

5. Note importanti: equals, hashCode ed efficienza

Perché è importante implementare correttamente equals e hashCode?

Tutte le operazioni sugli insiemi (Set) dipendono dalla correttezza dei metodi equals e hashCode. Se memorizzate oggetti di una vostra classe (ad esempio, Student), sovrascrivete sempre questi metodi; altrimenti i confronti non funzioneranno correttamente.

Esempio:

class Student {
    String name;
    int age;

    // Non dimenticare di sovrascrivere equals e hashCode!
}

Se non lo fate, due studenti con lo stesso nome e la stessa età saranno considerati oggetti diversi per il Set.

Perché è meglio usare Set e non List?

  • L’operazione contains su Set è veloce (di solito tempo costante).
  • In una List la ricerca di un elemento avviene in tempo lineare, il che può essere critico per collezioni grandi.
  • Per le operazioni sugli insiemi (union, intersection, difference) Set è molto più efficiente e naturale.

6. Errori tipici nel lavoro con le operazioni sugli insiemi

Errore n. 1: usare List al posto di Set per operazioni sugli insiemi. Se raccogliete gli elementi in List, i duplicati non vengono rimossi e l’operazione contains è lenta. Per union/intersection/difference usate Set.

Errore n. 2: equals/hashCode non implementati per gli oggetti. Se memorizzate in Set oggetti di una vostra classe ma non avete sovrascritto i metodi equals e hashCode, intersezione e differenza si comporteranno in modo “strano” — oggetti che in sostanza sono uguali non verranno considerati equivalenti.

Errore n. 3: modificare la collezione durante lo stream. Se provate a modificare direttamente il Set sorgente (ad esempio, aggiungendo o rimuovendo elementi) all’interno dello stream, otterrete una ConcurrentModificationException. Lavorate sempre con un nuovo insieme.

Errore n. 4: perdita di ordine non evidente. HashSet non garantisce l’ordine degli elementi. Se l’ordine è importante — usate LinkedHashSet o TreeSet.

Errore n. 5: usare Stream.concat per più di due collezioni. Stream.concat concatena solo due stream. Per un numero maggiore usate Stream.of(...) e flatMap.

Errore n. 6: problemi con null. Gli insiemi non amano i valori null, soprattutto se usate Set.of(...) — non ammette null. Per gestire null usate altre implementazioni oppure filtrate i valori in anticipo.

1
Compito
JAVA 25 SELF, livello 32, lezione 2
Bloccato
Individuazione dei sospetti unici da diverse fonti 🕵️‍♂️
Individuazione dei sospetti unici da diverse fonti 🕵️‍♂️
1
Compito
JAVA 25 SELF, livello 32, lezione 2
Bloccato
Catalogazione degli artefatti da diversi scavi archeologici 🏺
Catalogazione degli artefatti da diversi scavi archeologici 🏺
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION