JavaScript - Generating combinations from n arrays with m elements

前端 未结 10 1614
一个人的身影
一个人的身影 2020-11-22 04:10

I\'m having trouble coming up with code to generate combinations from n number of arrays with m number of elements in them, in JavaScript. I\'ve seen similar questions about

相关标签:
10条回答
  • 2020-11-22 04:52

    I suggest a simple recursive generator function:

    // Generate all combinations of array elements:
    function* cartesian(head, ...tail) {
      let remainder = tail.length ? cartesian(...tail) : [[]];
      for (let r of remainder) for (let h of head) yield [h, ...r];
    }
    
    
    // Example:
    for (let c of cartesian([0,1], [0,1,2,3], [0,1,2])) {
      console.log(...c);
    }

    0 讨论(0)
  • 2020-11-22 04:52

    You can use a recursive function to get all combinations

    const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
    
    let loopOver = (arr, str = '', final = []) => {
      if (arr.length > 1) {
        arr[0].forEach(v => loopOver(arr.slice(1), str + v, final))
      } else {
        arr[0].forEach(v => final.push(str + v))
      }
      return final
    }
    
    console.log(loopOver(charSet))


    This code can still be shorten using ternary but i prefer the first version for readability

    0 讨论(0)
  • 2020-11-22 04:53

    Here is a quite simple and short one using a recursive helper function:

    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;
    }
    

    Usage:

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

    To make the function take an array of arrays, just change the signature to function cartesian(args) instead of using rest parameter syntax.

    0 讨论(0)
  • 2020-11-22 05:03

    Here's another way of doing it. I treat the indices of all of the arrays like a number whose digits are all different bases (like time and dates), using the length of the array as the radix.

    So, using your first set of data, the first digit is base 2, the second is base 4, and the third is base 3. The counter starts 000, then goes 001, 002, then 010. The digits correspond to indices in the arrays, and since order is preserved, this is no problem.

    I have a fiddle with it working here: http://jsfiddle.net/Rykus0/DS9Ea/1/

    and here is the code:

    // Arbitrary base x number class 
    var BaseX = function(initRadix){
        this.radix     = initRadix ? initRadix : 1;    
        this.value     = 0;
        this.increment = function(){
            return( (this.value = (this.value + 1) % this.radix) === 0);
        }
    }
    
    function combinations(input){
        var output    = [],    // Array containing the resulting combinations
            counters  = [],    // Array of counters corresponding to our input arrays
            remainder = false, // Did adding one cause the previous digit to rollover?
            temp;              // Holds one combination to be pushed into the output array
    
        // Initialize the counters
        for( var i = input.length-1; i >= 0; i-- ){
            counters.unshift(new BaseX(input[i].length));
        }
    
        // Get all possible combinations
        // Loop through until the first counter rolls over
        while( !remainder ){
            temp      = [];   // Reset the temporary value collection array
            remainder = true; // Always increment the last array counter
    
            // Process each of the arrays
            for( i = input.length-1; i >= 0; i-- ){
                temp.unshift(input[i][counters[i].value]); // Add this array's value to the result
    
                // If the counter to the right rolled over, increment this one.
                if( remainder ){
                    remainder = counters[i].increment();
                }
            }
            output.push(temp); // Collect the results.
        }
    
        return output;
    }
    
    // Input is an array of arrays
    console.log(combinations([[0,1], [0,1,2,3], [0,1,2]]));
    
    0 讨论(0)
提交回复
热议问题