JavaScript: generación de combinaciones a partir de n matrices con m elementos [duplicado]

Resuelto quano asked hace 11 años • 10 respuestas

Tengo problemas para encontrar código para generar combinaciones a partir de n números de matrices con m números de elementos, en JavaScript. He visto preguntas similares sobre esto para otros idiomas, pero las respuestas incorporan magia sintáctica o de biblioteca que no estoy seguro de cómo traducir.

Considere estos datos:

[[0,1], [0,1,2,3], [0,1,2]]

3 matrices, con un número diferente de elementos en ellas. Lo que quiero hacer es obtener todas las combinaciones combinando un elemento de cada matriz.

Por ejemplo:

0,0,0 // item 0 from array 0, item 0 from array 1, item 0 from array 2
0,0,1
0,0,2
0,1,0
0,1,1
0,1,2
0,2,0
0,2,1
0,2,2

Etcétera.

Si el número de matrices fuera fijo, sería fácil realizar una implementación codificada. Pero la cantidad de matrices puede variar:

[[0,1], [0,1]]
[[0,1,3,4], [0,1], [0], [0,1]]

Cualquier ayuda sería muy apreciada.

quano avatar Mar 08 '13 23:03 quano
Aceptado

Aquí hay uno bastante simple y breve que utiliza una función auxiliar recursiva:

function cartesian(...args) {
    var r = [], max = args.length-1;
    function helper(arr, i) {
        for (var j=0, l=args[i].length; j<l; j++) {
            var a = arr.slice(0); // clone arr
            a.push(args[i][j]);
            if (i==max)
                r.push(a);
            else
                helper(a, i+1);
        }
    }
    helper([], 0);
    return r;
}

Uso:

cartesian([0,1], [0,1,2,3], [0,1,2]);

Para hacer que la función tome una matriz de matrices, simplemente cambie la firma a function cartesian(args)en lugar de usar la sintaxis del parámetro resto.

Bergi avatar Mar 09 '2013 11:03 Bergi

Sugiero una función generadora recursiva simple :

// JS
function* cartesianIterator(head, ...tail) {
  const remainder = tail.length ? cartesianIterator(...tail) : [[]];
  for (let r of remainder) for (let h of head) yield [h, ...r];
}

// get values:
const cartesian = items => [...cartesianIterator(items)];
console.log(cartesian(input));
// TS
function* cartesianIterator<T>(items: T[][]): Generator<T[]> {
  const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];
  for (let r of remainder) for (let h of items.at(0)!) yield [h, ...r];
}

// get values:
const cartesian = <T>(items: T[][]) => [...cartesianIterator(items)];
console.log(cartesian(input));

le_m avatar Jun 03 '2017 14:06 le_m