¿Cómo puedo crear todas las combinaciones posibles para el contenido de dos matrices?

Resuelto asked hace 12 años • 16 respuestas

Tengo dos matrices:

var array1 = ["A", "B", "C"];
var array2 = ["1", "2", "3"];

¿Cómo puedo configurar otra matriz para que contenga cada combinación de lo anterior, de modo que:

var combos = ["A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", "C3"];
 avatar Jan 20 '12 11:01
Aceptado

Por si alguien busca Array.mapuna solución

var array1=["A","B","C"];

var array2=["1","2","3","4"];

console.log(array1.flatMap(d => array2.map(v => d + v)))
Expandir fragmento

Nitish Narang avatar Nov 24 '2018 15:11 Nitish Narang

O si desea crear combinaciones con un número arbitrario de matrices de tamaños arbitrarios... (Estoy seguro de que puede hacer esto de forma recursiva, pero como esta no es una entrevista de trabajo, estoy usando un iterativo " Odómetro" para esto...incrementa un "número" con cada dígito un dígito "base-n" basado en la longitud de cada matriz)...por ejemplo...

combineArrays([ ["A","B","C"],
                ["+", "-", "*", "/"],
                ["1","2"] ] )

...devoluciones...

[
   "A+1","A+2","A-1", "A-2",
   "A*1", "A*2", "A/1", "A/2", 
   "B+1","B+2","B-1", "B-2",
   "B*1", "B*2", "B/1", "B/2", 
   "C+1","C+2","C-1", "C-2",
   "C*1", "C*2", "C/1", "C/2"
]

...cada uno de estos corresponde a un valor de "odómetro" que selecciona un índice de cada matriz...

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

El método del "odómetro" le permite generar fácilmente el tipo de salida que desea, no solo las cadenas concatenadas como las que tenemos aquí. Además de eso, al evitar la recursividad evitamos la posibilidad de... ¿me atrevo a decirlo? -- un desbordamiento de pila ...

function combineArrays( array_of_arrays ){

    // First, handle some degenerate cases...

    if( ! array_of_arrays ){
        // Or maybe we should toss an exception...?
        return [];
    }

    if( ! Array.isArray( array_of_arrays ) ){
        // Or maybe we should toss an exception...?
        return [];
    }

    if( array_of_arrays.length == 0 ){
        return [];
    }

    for( let i = 0 ; i < array_of_arrays.length; i++ ){
        if( ! Array.isArray(array_of_arrays[i]) || array_of_arrays[i].length == 0 ){
            // If any of the arrays in array_of_arrays are not arrays or zero-length, return an empty array...
            return [];
        }
    }

    // Done with degenerate cases...

    // Start "odometer" with a 0 for each array in array_of_arrays.
    let odometer = new Array( array_of_arrays.length );
    odometer.fill( 0 ); 

    let output = [];

    let newCombination = formCombination( odometer, array_of_arrays );

    output.push( newCombination );

    while ( odometer_increment( odometer, array_of_arrays ) ){
        newCombination = formCombination( odometer, array_of_arrays );
        output.push( newCombination );
    }

    return output;
}/* combineArrays() */


// Translate "odometer" to combinations from array_of_arrays
function formCombination( odometer, array_of_arrays ){
    // In Imperative Programmingese (i.e., English):
    // let s_output = "";
    // for( let i=0; i < odometer.length; i++ ){
    //    s_output += "" + array_of_arrays[i][odometer[i]]; 
    // }
    // return s_output;

    // In Functional Programmingese (Henny Youngman one-liner):
    return odometer.reduce(
      function(accumulator, odometer_value, odometer_index){
        return "" + accumulator + array_of_arrays[odometer_index][odometer_value];
      },
      ""
    );
}/* formCombination() */

function odometer_increment( odometer, array_of_arrays ){

    // Basically, work you way from the rightmost digit of the "odometer"...
    // if you're able to increment without cycling that digit back to zero,
    // you're all done, otherwise, cycle that digit to zero and go one digit to the
    // left, and begin again until you're able to increment a digit
    // without cycling it...simple, huh...?

    for( let i_odometer_digit = odometer.length-1; i_odometer_digit >=0; i_odometer_digit-- ){ 

        let maxee = array_of_arrays[i_odometer_digit].length - 1;         

        if( odometer[i_odometer_digit] + 1 <= maxee ){
            // increment, and you're done...
            odometer[i_odometer_digit]++;
            return true;
        }
        else{
            if( i_odometer_digit - 1 < 0 ){
                // No more digits left to increment, end of the line...
                return false;
            }
            else{
                // Can't increment this digit, cycle it to zero and continue
                // the loop to go over to the next digit...
                odometer[i_odometer_digit]=0;
                continue;
            }
        }
    }/* for( let odometer_digit = odometer.length-1; odometer_digit >=0; odometer_digit-- ) */

}/* odometer_increment() */
John D. Aynedjian avatar Jul 22 '2018 23:07 John D. Aynedjian

Viendo muchos forbucles en todas las respuestas...

Aquí se me ocurrió una solución recursiva que encontrará todas las combinaciones de N números de matrices tomando 1 elemento de cada matriz:

const array1=["A","B","C"]
const array2=["1","2","3"]
const array3=["red","blue","green"]

const combine = ([head, ...[headTail, ...tailTail]]) => {
  if (!headTail) return head

  const combined = headTail.reduce((acc, x) => {
    return acc.concat(head.map(h => `${h}${x}`))
  }, [])

  return combine([combined, ...tailTail])
}

console.log('With your example arrays:', combine([array1, array2]))
console.log('With N arrays:', combine([array1, array2, array3]))

//-----------UPDATE BELOW FOR COMMENT---------
// With objects
const array4=[{letter: "A"}, {letter: "B"}, {letter: "C"}]
const array5=[{number: 1}, {number: 2}, {number: 3}]
const array6=[{color: "RED"}, {color: "BLUE"}, {color: "GREEN"}]

const combineObjects = ([head, ...[headTail, ...tailTail]]) => {
  if (!headTail) return head

  const combined = headTail.reduce((acc, x) => {
    return acc.concat(head.map(h => ({...h, ...x})))
  }, [])

  return combineObjects([combined, ...tailTail])
}

console.log('With arrays of objects:', combineObjects([array4, array5, array6]))
Expandir fragmento

Cumulo Nimbus avatar Jul 13 '2019 03:07 Cumulo Nimbus

Suponiendo que esté utilizando un navegador web reciente compatible con Array.forEach:

var combos = [];
array1.forEach(function(a1){
  array2.forEach(function(a2){
    combos.push(a1 + a2);
  });
});

Si no lo tienes forEach, es un ejercicio bastante fácil reescribir esto sin él. Como otros han demostrado antes, también hay algunas ventajas de rendimiento al prescindir... (Aunque sostengo que dentro de poco, los tiempos de ejecución de JavaScript comunes optimizarán cualquier ventaja actual para hacer esto de otra manera).

ziesemer avatar Jan 20 '2012 04:01 ziesemer