HashSet

Correspondencia en Python —>

Un HashSet es una estructura de datos que no está ordenada. Es decir, no podemos acceder a un elemento en concreto como lo haríamos con un List o con ArrayList.

Puede contener varios tipos de elementos a la vez, aunque no es lo más recomendable, ya que tendríamos problemas si queremos hacer un recorrido completo por todos sus elementos, al no saber en cada momento con que elemento nos encontramos.

Una de sus características más importantes, es que sus elementos no se pueden repetir. Si intentamos añadir un elemento que ya está dentro del HashSet, sencillamente no lo va a añadir.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        double decimal=4.34;
        int entero=14;
        String palabra="Hola";
        List<Integer> mis_numeros = new ArrayList<>(Arrays.asList(1,2,3));
        Set nombres = new HashSet<>(Set.of("Ana",palabra,decimal, mis_numeros,mis_numeros.get(2)));
        System.out.println(nombres);
    }
}
Resultado:

[[1, 2, 3], 3, Ana, 4.34, Hola]

En el ejemplo anterior vemos cómo declarar e instanciar a la vez una estructura HashSet. Podemos observar que el elemento 3 aparece repetido, la explicación es muy sencilla, por un lado aparece como elemento y por otro aparece como perteneciente a una estructura de datos ArrayList (que es la que está incluida).

Para añadir elementos a un HashSet, tanto si ya está instanciado como si no, disponemos del método .add(elemento). Veamos ahora como declararlo primero e incluir los elementos después.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        double decimal=4.34;
        int entero=14;
        String palabra="Hola";
        List<Integer> mis_numeros = new ArrayList<>(Arrays.asList(1,2,3));
        Set nombres = new HashSet();
        nombres.add("Ana");
        nombres.add(palabra);
        nombres.add(decimal);
        nombres.add(mis_numeros);
        nombres.add(mis_numeros.get(2));
        System.out.println(nombres);
    }
}

Lo más habitual y sobre todo lo más operativo, es que el HashSet esté formado solo por elementos todos del mismo tipo. Para ello la forma de declararlo es un poco diferente y depende del tipo de datos que contenga.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(343,132,987,0,14,8734));
        System.out.println(mis_enteros);
    }
}
Resultado:

[0, 132, 343, 987, 8734, 14]

Tal y como estamos observando, la forma de almacenar y mostrar los elementos del HashSet es muy arbitraria, ya que no lleva ningún orden de entrada y almacenamiento.

Recorrer los elementos de un HashSet. Podemos recorrer sus elementos utilizando un bucle for:

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(343,132,987,0,14,8734));
        int suma=0;
        for (int entero: mis_enteros){
            suma=suma+entero;
        }
        System.out.println("La suma de todos los números es: "+suma);
    }
}
Resultado:

La suma de todos los números es: 10210

El método .contains(elemento) nos permite comprobar si un elemento está incluido dentro de un HashSet.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(343,132,987,0,14,8734));
        int ejemplo=132;
        if (mis_enteros.contains(ejemplo)){
            System.out.println("El número "+ejemplo+" está incluido.");
        }
    }
}
Resultado:

El número 132 está incluido.

El método .size( ) nos dará la cantidad de elementos que tiene el HashSet.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(343,132,987,0,14,8734));
        int longitud=mis_enteros.size();
        System.out.println("El conjunto tiene "+longitud+" elementos.");
    }
}
Resultado:

El conjunto tiene 6 elementos.

Si ya tenemos un HashSet, podemos añadirle todos los elementos de otro HashSet, de un List o un ArrayList con el método .addAll(otro) Esto sería el equivalente a la UNION entre conjuntos.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        List<Integer> mi_lista = new ArrayList<>(Arrays.asList(1,2,3,4,5));
        mis_enteros.addAll(mi_lista);
        System.out.println(mis_enteros);
    }
}
Resultado:

[2, 3, 132, 987, 8734, 14]
[1, 2, 3, 132, 4, 5, 987, 8734, 14]

Vemos que se han incluido 3 elementos más, aunque había 5 en el ArrayList. Esto es debido a que los elementos de un HashSet no se pueden repetir.

Con el método .remove(elemento) podemos eliminar un elemento del HashSet.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        mis_enteros.remove(132);
        System.out.println(mis_enteros);
    }
}
Resultado:

[2, 3, 132, 987, 14, 8734]
[2, 3, 987, 14, 8734]

Con el método .clear( ) eliminamos completamente todos los elementos del conjunto.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        mis_enteros.clear();
        System.out.println(mis_enteros);
    }
}
Resultado:

[2, 3, 132, 987, 14, 8734]
[ ]

Si tenemos un ArrayList le podemos añadir muy fácilmente todos los elementos que contiene un HashSet

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        ArrayList<Integer> miLista = new ArrayList<>();
        miLista.addAll(mis_enteros);
        System.out.println(miLista);
    }
}
Resultado:

[2, 3, 132, 987, 8734, 14]
[2, 3, 132, 987, 8734, 14]

La operación inversa también es posible, es decir, a partir de los elementos de un ArrayList podemos obtener un HashSet que contenga todos sus elementos.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {

        List<Integer> miLista = new ArrayList<>(Arrays.asList(3,132,987,2,14,8734));
        System.out.println(miLista);
        Set <Integer> mis_enteros= new HashSet<>();
        mis_enteros.addAll(miLista);
        System.out.println(mis_enteros);
    }
}
Resultado:

[3, 132, 987, 2, 14, 8734]
[2, 3, 132, 987, 14, 8734]

También podemos elegir qué segmento de ArrayList queremos que formen parte del nuevo HashSet

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {

        List<Integer> miLista = new ArrayList<>(Arrays.asList(3,132,987,2,14,8734));
        System.out.println(miLista);
        Set <Integer> mis_enteros= new HashSet<>();
        mis_enteros.addAll(miLista.subList(0,4));
        System.out.println(mis_enteros);
    }
}
Resultado:

[3, 132, 987, 2, 14, 8734]
[2, 3, 132, 987]

Antes hemos visto como si tenemos un HashSet, podemos también con .addAll obtener la unión con otro HashSet. Pero en este caso el primer HashSet se ve modificado para mostrar la unión.

Es probable que necesitemos conservar los dos tal y como están originariamente, y crear la unión en un nuevo HashSet. Esto es también muy sencillo.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        Set<Integer> mi_lista = new HashSet<>(Set.of(1,2,3,4,5));
        System.out.println(mi_lista);
        Set mi_union=new HashSet<>(mis_enteros);
        mi_union.addAll(mi_lista);
        System.out.println(mi_union);
    }
}
Resultado:

[2, 3, 132, 987, 14, 8734]
[1, 2, 3, 4, 5]
[1, 2, 3, 132, 4, 5, 987, 14, 8734]

Para crear la intersección de dos HashSet, podemos utilizar el método primerhash.retainAll(segundohash)

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        Set<Integer> mi_lista = new HashSet<>(Set.of(1,2,3,4,5));
        System.out.println(mi_lista);
        Set mi_interseccion=new HashSet<>(mis_enteros);
        mi_interseccion.retainAll(mi_lista);
        System.out.println(mi_interseccion);
    }
}
Resultado:

[2, 3, 132, 987, 8734, 14]
[1, 2, 3, 4, 5]
[2, 3]

Partiendo de un HashSet podemos restarle un segundo HashSet haciendo uso del método .removeAll( ) Con esto conseguimos eliminar del primero, todos los elementos que también se encuentren en el segundo.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        Set<Integer> mi_lista = new HashSet<>(Set.of(1,2,3,4,5));
        System.out.println(mi_lista);
        Set mi_resta=new HashSet<>(mis_enteros);
        mi_resta.removeAll(mi_lista);
        System.out.println(mi_resta);
    }
}
Resultado:

[2, 3, 132, 987, 8734, 14]
[1, 2, 3, 4, 5]
[132, 987, 8734, 14]

Hay otro concepto que se le suele llamar resta simétrica. Consiste en un nuevo HashSet que tenga todos elementos de primero que no estén en el segundo y a la vez todos los elementos del segundo que no estén en el primero. Es lo totalmente opuesto a la intersección de los dos HashSet.

Para obtener la resta simétrica, aplicamos la resta por separado a los dos HashSet y después unimos ambos resultados.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println(mis_enteros);
        Set<Integer> mi_lista = new HashSet<>(Set.of(1,2,3,4,5));
        System.out.println(mi_lista);
        Set mi_resta=new HashSet<>(mis_enteros);
        Set mi_otra_resta=new HashSet(mi_lista);
        mi_resta.removeAll(mi_lista);
        mi_otra_resta.removeAll(mis_enteros);
        mi_resta.addAll(mi_otra_resta);
        System.out.println("Resta simétrica: "+mi_resta);
    }
}
Resultado:

[2, 3, 132, 987, 14, 8734]
[1, 2, 3, 4, 5]
Resta simétrica: [1, 132, 4, 5, 987, 14, 8734]

Con el método .containsAll( ) podemos saber si un HashSet es un subconjunto de otro, dicho de otra manera si un HashSet es mayor que otro. Este mismo método nos puede valer para saber si dos HashSet son iguales.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        System.out.println("mis_enteros: "+mis_enteros);
        Set<Integer> mi_lista = new HashSet<>(Set.of(2,3,14,132));
        System.out.println("mi_lista: "+mi_lista);
        if (mis_enteros.containsAll(mi_lista)){
            if (mis_enteros.size() > mi_lista.size()){
                System.out.println("mi_lista es Subconjunto de mis_enteros.");
            }
            else{
                System.out.println("mi_lista y mis_enteros son iguales.");
            }
        }
    }
}
Resultado:

mis_enteros: [2, 3, 132, 987, 14, 8734]
mi_lista: [2, 3, 132, 14]
mi_lista es Subconjunto de mis_enteros.

Para saber si la intersección de dos HashSet es el conjunto vació, es decir que no tienen ningún elemento en común, podemos hacer uso de la función Collections.disjoint(set1, set2)

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        Set <Integer> otros_enteros= new HashSet<>(Set.of(923,1,5,78));

        System.out.println("mis_enteros: "+mis_enteros);
        System.out.println("otros_enteros: "+otros_enteros);

        if (Collections.disjoint(otros_enteros,mis_enteros)){
            System.out.println("No tienen ningún elemento en común");
        }
        else{
            System.out.println("Sí que tienen algún elemento en común.");
        }
    }
}
Resultado:

mis_enteros: [2, 3, 132, 987, 8734, 14]
otros_enteros: [1, 5, 923, 78]
No tienen ningún elemento en común

Para crear un duplicado de un HashSet pero que sea independiente al original no podemos usar cualquier método, ya que corremos el riesgo de obtener un duplicado con otro nombre, pero cuyos elementos sean iguales y dependientes entre los dos HashSet de tal forma que si añadimos (o borramos) un elemento en un HashSet, también se borre en el otro.

Lo mejor es partir de un HashSet vacío, a continuación recorrer el original e ir añadiendo elemento por elemento al nuevo.

import java.util.*;

public class Mis_HashSet {
    public static void main(String[] args) {
        Set <Integer> mis_enteros= new HashSet<>(Set.of(3,132,987,2,14,8734));
        Set mi_clonado = new HashSet();
        for (int entero: mis_enteros){
            mi_clonado.add(entero);
        }
        mi_clonado.remove(132);
        System.out.println("mis_enteros: "+mis_enteros);
        System.out.println("mi_clonado: "+mi_clonado);
    }
}
Resultado:

mis_enteros: [2, 3, 132, 987, 14, 8734]
mi_clonado: [2, 3, 987, 14, 8734]
InicioComandos JavaBloques de código.
Comentar códigoSystem.out.printScanner (System.in)
Captura de erroresStringDatos Numéricos
Elementos aleatoriosDatos Fecha/horaConstantes
Bucles forBucles whileBloque if
ArraysArrayListswitch case
HashSetHashMapMétodos.
ClasesArchivosEntorno gráfico Swing
JFrame (Ventanas)Componentes básicos.