CodeGym /Cursos /JAVA 25 SELF /Operaciones union, intersection, difference

Operaciones union, intersection, difference

JAVA 25 SELF
Nivel 32, Lección 2
Disponible

1. Operación union (unión de conjuntos)

En Java, para representar conjuntos se utiliza la interfaz Set<T>. A diferencia de las listas (List), los conjuntos garantizan la unicidad de los elementos y, por lo general, no se preocupan por el orden (a menos que se utilicen implementaciones especiales, por ejemplo, LinkedHashSet). Las implementaciones más populares — HashSet y TreeSet. Su tarea principal — determinar rápidamente la presencia de un elemento y asegurar la ausencia de duplicados.

¿Cuándo se necesitan conjuntos?

  • Cuando la unicidad es importante: por ejemplo, la lista de todos los usuarios únicos que han visitado el sitio.
  • Cuando hay que comprobar rápidamente la presencia de un elemento: el método contains de HashSet suele funcionar en tiempo constante.
  • Cuando se requieren operaciones típicas sobre conjuntos: unión, intersección, diferencia.

Union es la unión de dos o más conjuntos: el resultado contiene todos los elementos de ambos conjuntos de origen (sin repeticiones).

Ejemplo práctico

Supongamos que tenemos dos conjuntos de estudiantes que asisten a los clubes «Robótica» y «Programación»:

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

Necesitamos obtener el conjunto de todos los estudiantes que van al menos a un club.

Solución mediante Stream API

La forma más directa es concatenar ambos streams y recolectarlos en un Set:

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

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

Explicación:

  • Stream.concat concatena dos streams.
  • collect(Collectors.toSet()) recolecta los elementos en un conjunto (eliminando automáticamente duplicados).

Alternativa: más de dos conjuntos

Si tenemos tres o más clubes, usamos Stream.of y 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]

¿Por qué Set?
Porque Set elimina automáticamente los duplicados. Si recolectas en una List, los mismos nombres aparecerán varias veces.

2. Operación intersection (intersección de conjuntos)

Intersection son los elementos que están simultáneamente en ambos conjuntos.

Ejemplo práctico

Encontrar a los estudiantes que van tanto a «Robótica» como a «Programación»:

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

Solución mediante Stream API:

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

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

Explicación:
Recorremos a todos los miembros de «Robótica» y filtramos solo a quienes están en «Programación». El resultado es un conjunto con los nombres presentes en ambos clubes.

Método alternativo (sin Stream API)

Se puede usar el método incorporado retainAll (modifica el conjunto actual):

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

Pero en el contexto de Stream API ponemos el foco en los streams.

3. Operación difference (diferencia de conjuntos)

Difference son los elementos del primer conjunto que no están en el segundo.

Ejemplo práctico

Encontrar a los estudiantes que van solo a «Robótica», pero no a «Programación»:

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

Solución mediante Stream API:

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

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

Explicación:
Filtramos a los miembros de «Robótica», dejando solo a quienes no están en «Programación».

Método alternativo (sin Stream API)

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

4. Tareas prácticas: procesamiento de listas de usuarios

Tarea 1: Encontrar a los estudiantes que van solo a un club

Hay que saber quién va solo a «Robótica» o solo a «Programación», pero no a ambos a la vez. Esto es la diferencia simétrica (xor para conjuntos):

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]

Tarea 2: Lista de todos los estudiantes únicos de varios clubes

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

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

Tarea 3: Encontrar a los estudiantes que no van a ningún club

Supongamos que tenemos la lista de todos los alumnos de la clase:

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

Hay que saber quién no va a ningún 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. Notas importantes: equals, hashCode y eficiencia

¿Por qué es importante implementar correctamente equals y hashCode?

Todas las operaciones con conjuntos (Set) dependen de la corrección de los métodos equals y hashCode. Si almacenas objetos de tu propia clase (por ejemplo, Student), entonces es obligatorio sobrescribir estos métodos; de lo contrario, las comparaciones funcionarán de forma incorrecta.

Ejemplo:

class Student {
    String name;
    int age;

    // ¡No olvides sobrescribir equals y hashCode!
}

Si no se hace, dos estudiantes con el mismo nombre y edad se considerarán objetos distintos para Set.

¿Por qué es mejor usar Set y no List?

  • La operación contains en Set es rápida (normalmente en tiempo constante).
  • En List la búsqueda de un elemento es lineal, lo que puede ser crítico para colecciones grandes.
  • Para operaciones sobre conjuntos (union, intersection, difference) Set es mucho más eficiente y lógico.

6. Errores típicos al trabajar con operaciones sobre conjuntos

Error n.º 1: usar List en lugar de Set para operaciones de conjuntos. Si recolectas los elementos en una List, los duplicados no se eliminan y la operación contains funciona lentamente. Para union/intersection/difference usa Set.

Error n.º 2: no implementar equals/hashCode para los objetos. Si en un Set almacenas objetos de tu propia clase y no sobrescribes los métodos equals y hashCode, la intersección y la diferencia se comportarán de forma “extraña”: objetos que en esencia son iguales no se considerarán equivalentes.

Error n.º 3: modificación de la colección durante el stream. Si intentas modificar directamente el Set dentro del stream (por ejemplo, añadiendo o eliminando elementos), obtendrás ConcurrentModificationException. Trabaja siempre con un conjunto nuevo.

Error n.º 4: pérdida de orden no evidente. HashSet no garantiza el orden de los elementos. Si el orden es importante — utiliza LinkedHashSet o TreeSet.

Error n.º 5: usar Stream.concat para más de dos colecciones. Stream.concat concatena solo dos streams. Para una cantidad mayor utiliza Stream.of(...) y flatMap.

Error n.º 6: problemas con null. A los conjuntos no les gustan los valores null, especialmente si utilizas Set.of(...) — no admite null. Para trabajar con null usa otras implementaciones o filtra los valores de antemano.

1
Tarea
JAVA 25 SELF, nivel 32, lección 2
Bloqueada
Detección de sospechosos únicos a partir de diferentes fuentes 🕵️‍♂️
Detección de sospechosos únicos a partir de diferentes fuentes 🕵️‍♂️
1
Tarea
JAVA 25 SELF, nivel 32, lección 2
Bloqueada
Catalogación de artefactos de diferentes excavaciones arqueológicas 🏺
Catalogación de artefactos de diferentes excavaciones arqueológicas 🏺
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION