Как я могу создать любую возможную комбинацию для содержимого двух массивов? - PullRequest
11 голосов
/ 20 января 2012

У меня есть два массива:

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

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

Как мне установить другой массив, содержащий каждую комбинацию из вышеперечисленного, так что:

var combos=["A1","A2","A3","B1","B2","B3","C1","C2","C3"];

Ответы [ 8 ]

10 голосов
/ 23 июля 2018

Или, если вы хотите создать комбинации с произвольным числом массивов произвольных размеров ... (Я уверен, что вы можете сделать это рекурсивно, но, поскольку это не собеседование, вместо этого я использую итерационный «одометр» для этого ... он увеличивает "число" с каждой цифрой на цифру "base-n" на основе длины каждого массива) ... например ...

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

... возвращается ...

[
   "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"
]

... каждый из них соответствует значению одометра, которое выбирает индекс из каждого массива ...

[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]

Метод «одометр» позволяет легко генерировать тип вывода, который вы хотите, а не только объединенные строки как у нас здесь. Кроме того, избегая рекурсии мы избегаем возможности - смею ли я сказать это? - переполнение стека ...

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() */
7 голосов
/ 20 января 2012

Предполагается, что вы используете новейший веб-браузер с поддержкой Array.forEach:

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

Если у вас нет forEach, это достаточно простое упражнение, чтобы переписать его без него.Как уже доказывали другие, есть и некоторые преимущества в производительности, которые можно обойтись без ... (Хотя я утверждаю, что через некоторое время обычные среды выполнения JavaScript оптимизируют любые текущие преимущества, если делать это иначе.)

6 голосов
/ 20 января 2012

петля этой формы

combos = [] //or combos = new Array(2);

for(var i = 0; i < array1.length; i++)
{
     for(var j = 0; j < array2.length; j++)
     {
        //you would access the element of the array as array1[i] and array2[j]
        //create and array with as many elements as the number of arrays you are to combine
        //add them in
        //you could have as many dimensions as you need
        combos.push(array1[i] + array2[j])
     }
}
3 голосов
/ 24 ноября 2018

На всякий случай, если кто-то ищет решение Array.map

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

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

console.log(array1.flatMap(d => array2.map(v => d + v)))
3 голосов
/ 04 апреля 2018

Вот функциональное решение ES6 для программирования:

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

var result = array1.reduce( (a, v) =>
    [...a, ...array2.map(x=>v+x)],
[]);
/*---------OR--------------*/
var result1 = array1.reduce( (a, v, i) =>
    a.concat(array2.map( w => v + w )),
[]);

/*-------------OR(without arrow function)---------------*/
var result2 = array1.reduce(function(a, v, i) {
    a = a.concat(array2.map(function(w){
      return v + w
    }));
    return a;
    },[]
);

console.log(result);
console.log(result1);
console.log(result2)
0 голосов
/ 13 июля 2019

Просмотр большого количества циклов for во всех ответах ...

Вот рекурсивное решение, которое я придумала, которое найдет все комбинации из числа N массивов, взяв 1 элемент из каждого массива:

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]))
0 голосов
/ 22 февраля 2019

У меня было похожее требование, но мне нужно было получить все комбинации клавиш объекта, чтобы можно было разбить его на несколько объектов. Например, мне нужно было преобразовать следующее:

{ key1: [value1, value2], key2: [value3, value4] }

в следующие 4 объекта

{ key1: value1, key2: value3 }
{ key1: value1, key2: value4 }
{ key1: value2, key2: value3 }
{ key1: value2, key2: value4 }

Я решил это с помощью функции ввода splitToMultipleKeys и рекурсивной функции spreadKeys;

function spreadKeys(master, objects) {
  const masterKeys = Object.keys(master);
  const nextKey = masterKeys.pop();
  const nextValue = master[nextKey];
  const newObjects = [];
  for (const value of nextValue) {
    for (const ob of objects) {
      const newObject = Object.assign({ [nextKey]: value }, ob);
      newObjects.push(newObject);
    }
  }

  if (masterKeys.length === 0) {
    return newObjects;
  }

  const masterClone = Object.assign({}, master);
  delete masterClone[nextKey];
  return spreadKeys(masterClone, newObjects);
}

export function splitToMultipleKeys(key) {
  const objects = [{}];
  return spreadKeys(key, objects);
}
0 голосов
/ 04 апреля 2018

Создайте такой цикл ->

let numbers = [1,2,3,4,5];
let letters = ["A","B","C","D","E"];
let combos = [];

for(let i = 0; i < numbers.length; i++) {

combos.push(letters[i] + numbers[i]);

};

Но вы должны сделать массив «цифр» и «букв» одинаковой длины!

...