21. Aplicaciones del producto cartesiano

El producto cartesiano permite generar combinaciones ordenadas entre conjuntos. Esta idea aparece en variantes de productos, pruebas de software, bases de datos, grafos, relaciones y configuraciones.

21.1 Introducción

El producto cartesiano no es solo una construcción teórica. En informática aparece cada vez que necesitamos combinar opciones de distintos conjuntos y considerar todas las posibilidades ordenadas.

En este tema veremos aplicaciones concretas: variantes de productos, generación de casos de prueba, relaciones entre entidades, coordenadas, grafos y combinaciones de configuración.

21.2 Recordatorio del concepto

El producto cartesiano de A y B contiene todos los pares ordenados cuyo primer componente pertenece a A y cuyo segundo componente pertenece a B.

A × B = {(a, b) | a ∈ A y b ∈ B}

Si A tiene 3 elementos y B tiene 2, entonces A × B tiene 6 pares.

21.3 Variantes de productos

Una aplicación directa del producto cartesiano es generar variantes a partir de opciones. Por ejemplo, talles y colores.

Talles = {S, M, L} Colores = {negro, blanco} Talles × Colores = {(S, negro), (S, blanco), (M, negro), (M, blanco), (L, negro), (L, blanco)}

Cada par representa una variante posible de un producto.

21.4 Variantes en JavaScript

Podemos generar todas las variantes con una función de producto cartesiano.

function productoCartesiano(a, b) {
  return a.flatMap(elementoA =>
    b.map(elementoB => [elementoA, elementoB])
  );
}

const talles = ["S", "M", "L"];
const colores = ["negro", "blanco"];

console.log(productoCartesiano(talles, colores));

El resultado contiene todas las combinaciones de talle y color.

21.5 Casos de prueba

En pruebas de software, el producto cartesiano permite generar combinaciones de parámetros.

Navegadores = {Chrome, Firefox} Sistemas = {Windows, Linux, macOS} Navegadores × Sistemas

Este producto genera escenarios como (Chrome, Windows), (Chrome, Linux) o (Firefox, macOS).

21.6 Generar pruebas en JavaScript

function productoCartesiano(a, b) {
  return a.flatMap(elementoA =>
    b.map(elementoB => [elementoA, elementoB])
  );
}

const navegadores = ["Chrome", "Firefox"];
const sistemas = ["Windows", "Linux", "macOS"];

const casos = productoCartesiano(navegadores, sistemas);

casos.forEach(([navegador, sistema]) => {
  console.log(`Probar en ${navegador} sobre ${sistema}`);
});

Cada par representa un caso de prueba distinto.

21.7 Bases de datos y combinaciones de entidades

En bases de datos, un producto cartesiano puede representar todas las combinaciones posibles entre registros de dos tablas. Esto puede ser útil, pero también peligroso si se hace sin condiciones.

Clientes × Productos

Si hay 100 clientes y 50 productos, el producto cartesiano tiene 5.000 pares. Por eso, en consultas reales se suelen agregar condiciones para obtener relaciones relevantes.

21.8 Relaciones como subconjuntos

Una relación entre dos conjuntos puede verse como un subconjunto del producto cartesiano.

Usuarios × Permisos = todos los pares posibles Relación asignado = pares donde el usuario tiene ese permiso

No todos los pares posibles tienen que formar parte de la relación. La relación selecciona solo los pares válidos.

21.9 Ejemplo de relación usuario-permiso

function productoCartesiano(a, b) {
  return a.flatMap(elementoA =>
    b.map(elementoB => [elementoA, elementoB])
  );
}

const usuarios = ["Ana", "Luis"];
const permisos = ["leer", "editar", "publicar"];

const paresPosibles = productoCartesiano(usuarios, permisos);

const permisosAsignados = [
  ["Ana", "leer"],
  ["Ana", "editar"],
  ["Luis", "leer"]
];

console.log(paresPosibles);
console.log(permisosAsignados);

Los pares posibles forman el producto cartesiano. Los permisos asignados forman una relación particular dentro de ese producto.

21.10 Grafos dirigidos

En un grafo dirigido, una arista puede representarse como un par ordenado (origen, destino). Si tenemos un conjunto de nodos, el producto cartesiano de nodos por nodos representa todas las aristas dirigidas posibles.

Nodos = {A, B, C} Nodos × Nodos = posibles aristas dirigidas

Luego, el grafo real se define como un subconjunto de esas aristas posibles.

21.11 Coordenadas y grillas

Una grilla rectangular puede verse como el producto cartesiano entre filas y columnas.

Filas = {1, 2, 3} Columnas = {A, B, C} Filas × Columnas = posiciones de la grilla

Cada par ordenado identifica una celda.

21.12 Generar una grilla en JavaScript

function productoCartesiano(a, b) {
  return a.flatMap(elementoA =>
    b.map(elementoB => [elementoA, elementoB])
  );
}

const filas = [1, 2, 3];
const columnas = ["A", "B", "C"];

const celdas = productoCartesiano(filas, columnas);

console.log(celdas);

El resultado contiene las posiciones [1, "A"], [1, "B"], [1, "C"] y así sucesivamente.

21.13 Producto cartesiano de más de dos conjuntos

Algunas aplicaciones necesitan combinar más de dos dimensiones. Por ejemplo: talle, color y material.

Talles × Colores × Materiales

El resultado está formado por ternas ordenadas.

function productoMultiple(...conjuntos) {
  return conjuntos.reduce(
    (resultado, conjunto) =>
      resultado.flatMap(parcial =>
        conjunto.map(elemento => [...parcial, elemento])
      ),
    [[]]
  );
}

const talles = ["S", "M", "L"];
const colores = ["negro", "blanco"];
const materiales = ["algodón", "poliéster"];
const variantesCompletas = productoMultiple(talles, colores, materiales);

console.log(variantesCompletas);

21.14 Crecimiento de combinaciones

La cantidad de combinaciones crece multiplicando las cardinalidades de los conjuntos.

|A × B × C| = |A| · |B| · |C|
Conjuntos Cardinalidades Combinaciones
Talles × colores 3 × 2 6
Navegadores × sistemas × idiomas 3 × 4 × 2 24
5 opciones con 4 valores cada una 4 × 4 × 4 × 4 × 4 1.024

En programación, esta multiplicación puede generar muchos casos rápidamente.

21.15 Aplicaciones resumidas

Aplicación Producto cartesiano Resultado
Productos Talles × colores Variantes
Testing Navegadores × sistemas Casos de prueba
Permisos Usuarios × permisos Pares posibles de asignación
Grafos Nodos × nodos Aristas dirigidas posibles
Grillas Filas × columnas Celdas

21.16 Errores frecuentes

  • Generar todas las combinaciones sin considerar el tamaño resultante.
  • Confundir producto cartesiano con combinación sin orden.
  • Olvidar que las relaciones suelen ser subconjuntos del producto cartesiano, no necesariamente el producto completo.
  • Usar producto cartesiano en bases de datos sin condiciones de relación.
  • Confundir pares posibles con pares válidos para un problema concreto.

21.17 Qué debes recordar de este tema

  • El producto cartesiano genera combinaciones ordenadas.
  • Sirve para variantes, pruebas, relaciones, grillas y grafos.
  • Una relación puede verse como un subconjunto del producto cartesiano.
  • La cantidad de resultados se obtiene multiplicando cardinalidades.
  • El crecimiento de combinaciones puede ser costoso.
  • En JavaScript, flatMap y map permiten generar productos cartesianos.

21.18 Conclusión

El producto cartesiano es una herramienta para construir posibilidades ordenadas. Su valor práctico aparece en muchas áreas de programación: desde variantes de productos hasta relaciones, grafos y pruebas automatizadas.

En el próximo tema estudiaremos el concepto de relación.