¿Qué es un Set?

Conjuntos: Estructura de datos no repetidos


Los Set en Javascript son estructuras de datos nativas muy interesantes para representar conjuntos de datos. La característica principal es que los datos insertados no se pueden repetir.

const set = new Set();                    // Set({})               (Conjunto vacío)
const set = new Set([5, 6, 7, 8, 9]);     // Set({5, 6, 7, 8, 9})  (Conjunto con 5 elementos)
const set = new Set([5, 5, 7, 8, 9]);     // Set({5, 7, 8, 9})     (Conjunto con 4 elementos)

set.constructor.name;                     // "Set"

En los sets se puede incluir cualquier tipo de elemento, sin embargo, existe otra estructura derivada de los Set que veremos más adelante que tiene ciertas diferencias y restricciones.

¿Qué son los Set?

Como hemos dicho, la característica principal de los conjuntos es que es una estructura que no permite valores repetidos, por lo que si intentamos insertar un valor que ya existe, no se insertará de nuevo y, por lo tanto, puedes tener la seguridad que un Set nunca tendrá el mismo elemento almacenado, despreocupándote por ejemplo, si tienes que asegurarte de que no existan elementos duplicados, ya que es un caso que no puede ocurrir.

Propiedad o Método Descripción
.size Propiedad que devuelve el número de elementos que tiene el conjunto.
.add(element) Añade un elemento al conjunto (si no está repetido) y devuelve el set. Muta
.has(element) Comprueba si element ya existe en el conjunto. Devuelve si existe.
.delete(element) Elimina el element del conjunto. Devuelve si lo eliminó correctamente.
.clear() Vacía el conjunto completo.

Vamos a analizar los diferentes métodos y propiedades que poseen los conjuntos.

Propiedad size

Si quieres saber cuántos elementos tienes en el conjunto, puedes utilizar la propiedad .size, que funciona de forma muy similar al .length de los array, por ejemplo.

const set = new Set();
set.size;    // 0

const set = new Set([5, 6, 7, 8]);
set.size;    // 4

const set = new Set([5, 6, 7, 8, 8]);
set.size;    // 4 (El 8 sólo se inserta una vez)

Métodos

Veamos ahora los diferentes métodos que tienen las estructuras de conjuntos Set.

Añadir elementos (add)

En primer lugar, el método .add() permite añadir un elemento al conjunto. Recuerda que aunque hasta ahora hemos utilizado sólo números, en el conjunto pueden insertarse otros tipos de elementos.

const set = new Set();

set.add(5);
set.add("A");
set.add(5);     // No se inserta

set;            // Set({5, "A"})

Observa que si intentamos añadir un elemento ya existente, no nos dará error, pero simplemente no se volverá a insertar. El método .add() devuelve el set con la inserción realizada, es decir, devuelve una referencia al conjunto.

Comprobar si existen (has)

Para comprobar si un elemento existe en un conjunto, podemos utilizar el método .has(). Este método devuelve un , por lo que si existe, nos devolverá true. De lo contrario, false.

const set = new Set([1, 2, 3]);

set.has(2);     // true
set.has(34);    // false
set.add(34);
set.has(34);    // true

Borrar elementos (delete)

Si necesitamos borrar algún elemento del conjunto, podemos utilizar el método .delete(). Al igual que el anterior, devuelve un . Si el borrado se realizó con éxito, devolverá true, si no pudo realizarse (no existe el elemento), devolverá false.

const set = new Set([1, 2, 3]);

set.delete(3);    // true
set.delete(39);   // false

set;              // Set({1, 2})

Vacíar conjunto (clear)

Si por otro lado, queremos hacer un borrado completo de los elementos, utilizaremos el método .clear(), que no devuelve nada. Simplemente borrará todos los elementos del conjunto y lo dejará vacío.

const set = new Set([1, 2, 3]);

set.clear();

set.size;         // 0

Convertir a Arrays

Una de las cosas más interesantes y útiles de los Set, es que al ser una estructura iterable (se puede recorrer), es muy sencillo utilizar desestructuración y convertirlo a un array (o viceversa):

const set = new Set([5, "A", [99, 10, 24]]);

set.size;                 // 3 (Contiene 3 elementos)
set.constructor.name;     // "Set"
const array = [...set];

array.constructor.name;   // "Array"
array;                    // [5, "A", [99, 10, 24]]

Cuidado cuando tengas conjuntos con tipos de datos más complejos con elementos anidados (arrays, objetos, etc...). Recuerda que son referencias y modificar un elemento referenciado, modificará el original.

Para evitar esto de forma sencilla, puedes utilizar la función structuredClone():

const set = new Set([5, "A", [99, 10, 24]]);
set.size;  // 3

const clonedArray = [...structuredClone(set)];
const array = [...set];

clonedArray[2][0] = "Modified";
[...set][2][0];   // 99 (El original se mantiene intacto)

array[2][0] = "Modified";
[...set][2][0];   // "Modified" (El original ha mutado)

Además, también puedes hacer la operación inversa, para convertir un array en un Set:

const array = [5, 4, 3, 3, 4];

const set = new Set(array);

set;   // Set({ 5, 4, 3 })

¿Qué son los WeakSet?

A grandes rasgos, los WeakSet son otro tipo de estructura de conjuntos, muy similar a Set (también impide introducir elementos duplicados), sin embargo, tiene algunos matices y diferencias. Veamos esas diferencias.

Diferencias con los Set

Los Set son una estructura de datos poco restrictiva, ya que puedes insertar cualquier tipo de elemento. Los WeakSet no permiten insertar datos primitivos:

// *** Set
const set = new Set([1, "A", true]);                 // OK
const set = new Set([{ name: "Manz" }, [2, 30]]);    // OK

// *** WeakSet
const set = new WeakSet([1, "A", true]);
// ERROR: Uncaught TypeError: Invalid value used in weak set

const set = new WeakSet([{ name: "Manz" }, [2, 30]]); // OK

Por otro lado, los WeakSet utilizan referencias débiles a un objeto, es decir, si ese objeto no se utiliza (no está referenciado) en ninguna otra parte del código, se eliminará del WeakSet en cuanto el Garbage Collector (Recolector de basura) lo decida para liberar memoria:

let element = { name: "Manz" };

const set = new WeakSet([element]);
set;    // WeakSet({ { name: "Manz" } })

element = null;
set;    // WeakSet({})

Observa que la penúltima línea, reasignamos a null la variable element. En ese caso, la zona de memoria donde está guardada la información { name: "Manz" } no está referenciada en ninguna otra variable, por lo que Javascript considera que ya no es útil, y la borra del WeakSet y de memoria.

OJO, es muy posible que al ejecutar este código y reasignar a null, la información aún permanezca en el set. Esto ocurre porque la recolección de basura es un proceso que no ocurre instantáneamente, sino que se dispara cuando el navegador lo considera oportuno y necesita o necesitará memoria adicional.

Tabla de resumen de diferencias

A continuación, una tabla resumen de las diferencias entre Set y WeakSet:

Característica Set WeakSet
Se pueden insertar elementos repetidos
Se pueden insertar elementos primitivos
Si no se usa el elemento, se elimina del set
Se puede convertir a array (es iterable)
Propiedad .size
Método .add()
Método .has()
Método .delete()
Método .clear()

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev