javascript 如何为两个数组的内容创建所有可能的组合?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8936610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 05:03:37  来源:igfitidea点击:

How can I create every combination possible for the contents of two arrays?

javascriptarraysfunctioncombinations

提问by John D. Aynedjian

I have two arrays:

我有两个数组:

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

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

How can I set another array to contain every combination of the above, so that:

如何设置另一个数组以包含上述所有组合,以便:

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

采纳答案by rubixibuc

A loop of this form

这种形式的循环

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])
     }
}

回答by John D. Aynedjian

Or if you'd like to create combinations with an arbitrary number of arrays of arbitrary sizes...(I'm sure you can do this recursively, but since this isn't a job interview, I'm instead using an iterative "odometer" for this...it increments a "number" with each digit a "base-n" digit based on the length of each array)...for example...

或者,如果您想使用任意数量的任意大小的数组创建组合...(我确定您可以递归地执行此操作,但是由于这不是求职面试,我改为使用迭代“ odometer”为此......它根据每个数组的长度增加一个“数字”,每个数字都是一个“base-n”数字)......例如......

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

...returns...

...返回...

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

...each of these corresponding to an "odometer" value that picks an index from each array...

...每一个都对应一个“里程表”值,从每个数组中选择一个索引......

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

The "odometer" method allows you to easily generate the type of output you want, not just the concatenated strings like we have here. Besides that, by avoiding recursion we avoid the possibility of -- dare I say it? -- a stack overflow...

“里程表”方法允许您轻松生成所需的输出类型,而不仅仅是像我们这里那样的连接字符串。除此之外,通过避免递归,我们避免了——我敢说吗?--堆栈溢出...

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() */

回答by ziesemer

Assuming you're using a recent web browser with support for Array.forEach:

假设您使用的是最近支持的 Web 浏览器Array.forEach

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

If you don't have forEach, it is an easy enough exercise to rewrite this without it. As others have proven before, there's also some performance advantages to doing without... (Though I contend that not long from now, the common JavaScript runtimes will optimize away any current advantages to doing this otherwise.)

如果您没有forEach,那么在没有它的情况下重写它是一个足够简单的练习。正如其他人之前已经证明的那样,不这样做也有一些性能优势......(尽管我认为不久之后,常见的 JavaScript 运行时将优化掉任何当前的优势,否则这样做。)

回答by Nitish Narang

Just in case anyone is looking for Array.mapsolution

以防万一有人正在寻找Array.map解决方案

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

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

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

回答by yajiv

Here is functional programming ES6 solution:

这是函数式编程 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)

回答by John D. Aynedjian

Part II: After my complicated iterative "odometer" solution of July 2018, here's a simpler recursive version of combineArraysRecursively()...

第二部分:在我 2018 年 7 月的复杂迭代“里程表”解决方案之后,这是一个更简单的 combineArraysRecursively() 递归版本......

function combineArraysRecursively( 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 are zero-length array, return an empty array...
                return [];
            }
        }

        // Done with degenerate cases...
        let outputs = [];

        function permute(arrayOfArrays, whichArray=0, output=""){

            arrayOfArrays[whichArray].forEach((array_element)=>{
                if( whichArray == array_of_arrays.length - 1 ){            
                    // Base case...
                    outputs.push( output + array_element );
                }
                else{
                    // Recursive case...
                    permute(arrayOfArrays, whichArray+1, output + array_element );
                }
            });/*  forEach() */
        }

        permute(array_of_arrays);

        return outputs;
        

}/* function combineArraysRecursively() */

const array1 = ["A","B","C"];
const array2 = ["+", "-", "*", "/"];
const array3 = ["1","2"];

console.log("combineArraysRecursively(array1, array2, array3) = ", combineArraysRecursively([array1, array2, array3]) );

回答by Cumulo Nimbus

Seeing a lot of forloops in all of the answers...

for在所有答案中看到很多循环......

Here's a recursive solution I came up with that will find all combinations of N number of arrays by taking 1 element from each array:

这是我想出的递归解决方案,它将通过从每个数组中取出 1 个元素来找到 N 个数组的所有组合:

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

回答by Steztric

I had a similar requirement, but I needed get all combinations of the keys of an object so that I could split it into multiple objects. For example, I needed to convert the following;

我有一个类似的要求,但我需要获取对象键的所有组合,以便我可以将其拆分为多个对象。例如,我需要转换以下内容;

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

into the following 4 objects

进入以下4个对象

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

I solved this with an entry function splitToMultipleKeysand a recursive function spreadKeys;

我用一个入口函数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);
}

回答by AquaDev

Make a loop like this ->

做一个这样的循环 - >

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]);

};

But you should make the array of “numbers” and “letters” at the same length thats it!

但是你应该让“数字”和“字母”的数组长度相同,就是这样!