Los conjuntos aparecen en programación cada vez que trabajamos con pertenencia, duplicados, filtros, permisos, coincidencias, diferencias y combinaciones de datos.
La teoría de conjuntos no es solo una herramienta matemática. En programación, muchas operaciones cotidianas son aplicaciones directas de conceptos como pertenencia, unión, intersección, diferencia y cardinalidad.
JavaScript incluye la estructura Set, que permite representar colecciones de valores únicos y realizar operaciones útiles sobre ellas.
Una de las aplicaciones más comunes de los conjuntos es eliminar valores repetidos.
const etiquetas = ["web", "datos", "web", "api", "datos"];
const etiquetasUnicas = new Set(etiquetas);
console.log([...etiquetasUnicas]);
El conjunto conserva cada etiqueta una sola vez.
Un conjunto permite preguntar si un elemento está presente.
const rolesPermitidos = new Set(["admin", "editor"]);
const rolUsuario = "editor";
console.log(rolesPermitidos.has(rolUsuario));
La operación has representa la idea matemática de pertenencia.
Los permisos requeridos para una acción pueden compararse con los permisos asignados a un usuario.
function esSubconjunto(a, b) {
return [...a].every(elemento => b.has(elemento));
}
const requeridos = new Set(["leer", "editar"]);
const asignados = new Set(["leer", "editar", "publicar"]);
console.log(esSubconjunto(requeridos, asignados));
La acción está permitida si los permisos requeridos son subconjunto de los asignados.
La unión permite combinar resultados de distintas fuentes sin repetir elementos.
function union(a, b) {
return new Set([...a, ...b]);
}
const porTitulo = new Set(["curso-js", "curso-sql"]);
const porEtiqueta = new Set(["curso-js", "curso-html"]);
console.log([...union(porTitulo, porEtiqueta)]);
El resultado reúne todos los cursos encontrados por cualquiera de los criterios.
La intersección permite encontrar elementos que cumplen dos condiciones al mismo tiempo.
function interseccion(a, b) {
return new Set([...a].filter(elemento => b.has(elemento)));
}
const activos = new Set(["Ana", "Luis", "Carla"]);
const suscriptos = new Set(["Luis", "Carla", "Marta"]);
console.log([...interseccion(activos, suscriptos)]);
El resultado contiene usuarios activos y suscriptos.
La diferencia permite encontrar elementos que están en un conjunto pero no en otro.
function diferencia(a, b) {
return new Set([...a].filter(elemento => !b.has(elemento)));
}
const esperados = new Set(["inicio", "perfil", "configuracion"]);
const implementados = new Set(["inicio", "perfil"]);
console.log([...diferencia(esperados, implementados)]);
El resultado muestra funcionalidades esperadas que todavía no están implementadas.
La diferencia simétrica muestra elementos que están en una colección u otra, pero no en ambas.
function union(a, b) {
return new Set([...a, ...b]);
}
function diferencia(a, b) {
return new Set([...a].filter(elemento => !b.has(elemento)));
}
function diferenciaSimetrica(a, b) {
return union(diferencia(a, b), diferencia(b, a));
}
const antes = new Set(["leer", "editar", "publicar"]);
const despues = new Set(["leer", "publicar", "eliminar"]);
console.log([...diferenciaSimetrica(antes, despues)]);
El resultado contiene permisos que cambiaron entre dos versiones.
La cardinalidad de un conjunto se obtiene con size.
const visitantes = new Set(["Ana", "Luis", "Ana", "Carla"]);
console.log(visitantes.size);
La cardinalidad indica cuántos visitantes únicos hay.
Las relaciones de equivalencia aparecen cuando agrupamos datos por una clave común.
const productos = [
{ nombre: "teclado", categoria: "perifericos" },
{ nombre: "mouse", categoria: "perifericos" },
{ nombre: "monitor", categoria: "pantallas" }
];
const porCategoria = productos.reduce((grupos, producto) => {
const clave = producto.categoria;
grupos[clave] ??= [];
grupos[clave].push(producto.nombre);
return grupos;
}, {});
console.log(porCategoria);
Cada categoría funciona como una clase de equivalencia.
El producto cartesiano permite generar combinaciones de opciones.
function productoCartesiano(a, b) {
return a.flatMap(x => b.map(y => [x, y]));
}
const talles = ["S", "M", "L"];
const colores = ["negro", "blanco"];
console.log(productoCartesiano(talles, colores));
Cada par representa una variante posible.
Una relación puede representarse como un conjunto de pares ordenados.
const usuarioPermiso = [
["Ana", "leer"],
["Ana", "editar"],
["Luis", "leer"]
];
console.log(usuarioPermiso);
Esta estructura representa qué permisos tiene cada usuario.
Un filtro construye un subconjunto de una colección original.
const usuarios = [
{ nombre: "Ana", activo: true },
{ nombre: "Luis", activo: false },
{ nombre: "Carla", activo: true }
];
const activosFiltrados = usuarios.filter(usuario => usuario.activo);
console.log(activosFiltrados);
El resultado es el subconjunto de usuarios activos.
Comparar conjuntos permite verificar si dos resultados contienen los mismos elementos sin importar el orden.
function sonIguales(a, b) {
return a.size === b.size && [...a].every(elemento => b.has(elemento));
}
const resultadoA = new Set(["a", "b", "c"]);
const resultadoB = new Set(["c", "b", "a"]);
console.log(sonIguales(resultadoA, resultadoB));
La igualdad de conjuntos no depende del orden de inserción.
| Concepto | Aplicación en programación | Ejemplo |
|---|---|---|
| Pertenencia | Validar existencia | Rol permitido |
| Unión | Combinar resultados | Búsqueda por texto o etiqueta |
| Intersección | Aplicar condiciones simultáneas | Usuarios activos y suscriptos |
| Diferencia | Detectar faltantes | Permisos requeridos no asignados |
| Cardinalidad | Contar únicos | Visitantes distintos |
La teoría de conjuntos ofrece un lenguaje práctico para resolver problemas de programación. Permite modelar pertenencia, unicidad, filtros, combinaciones, relaciones y comparaciones de datos.
En el próximo tema estudiaremos aplicaciones de conjuntos en estructuras de datos.