JavaScript - Generating combinations from n arrays with m elements

前端 未结 10 1613
一个人的身影
一个人的身影 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:41

    Another implementation with ES6 recursive style

    Array.prototype.cartesian = function(a,...as){
      return a ? this.reduce((p,c) => (p.push(...a.cartesian(...as).map(e => as.length ? [c,...e] : [c,e])),p),[])
               : this;
    };
    
    console.log(JSON.stringify([0,1].cartesian([0,1,2,3], [[0],[1],[2]])));

    0 讨论(0)
  • 2020-11-22 04:42
    var f = function(arr){
        if(typeof arr !== 'object'){
            return false;
        }
    
        arr = arr.filter(function(elem){ return (elem !== null); }); // remove empty elements - make sure length is correct
        var len = arr.length;
    
        var nextPerm = function(){ // increase the counter(s)
            var i = 0;
    
            while(i < len)
            {
                arr[i].counter++;
    
                if(arr[i].counter >= arr[i].length){
                    arr[i].counter = 0;
                    i++;
                }else{
                    return false;
                }
            }
    
            return true;
        };
    
        var getPerm = function(){ // get the current permutation
            var perm_arr = [];
    
            for(var i = 0; i < len; i++)
            {
                perm_arr.push(arr[i][arr[i].counter]);
            }
    
            return perm_arr;
        };
    
        var new_arr = [];
    
        for(var i = 0; i < len; i++) // set up a counter property inside the arrays
        {
            arr[i].counter = 0;
        }
    
        while(true)
        {
            new_arr.push(getPerm()); // add current permutation to the new array
    
            if(nextPerm() === true){ // get next permutation, if returns true, we got them all
                break;
            }
        }
    
        return new_arr;
    };
    
    0 讨论(0)
  • 2020-11-22 04:45

    Just for fun, here's a more functional variant of the solution in my first answer:

    function cartesian() {
        var r = [], args = Array.from(arguments);
        args.reduceRight(function(cont, factor, i) {
            return function(arr) {
                for (var j=0, l=factor.length; j<l; j++) {
                    var a = arr.slice(); // clone arr
                    a[i] = factor[j];
                    cont(a);
                }
            };
        }, Array.prototype.push.bind(r))(new Array(args.length));
        return r;
    }
    

    Alternative, for full speed we can dynamically compile our own loops:

    function cartesian() {
        return (cartesian.cache[arguments.length] || cartesian.compile(arguments.length)).apply(null, arguments);
    }
    cartesian.cache = [];
    cartesian.compile = function compile(n) {
        var args = [],
            indent = "",
            up = "",
            down = "";
        for (var i=0; i<n; i++) {
            var arr = "$"+String.fromCharCode(97+i),
                ind = String.fromCharCode(105+i);
            args.push(arr);
            up += indent+"for (var "+ind+"=0, l"+arr+"="+arr+".length; "+ind+"<l"+arr+"; "+ind+"++) {\n";
            down = indent+"}\n"+down;
            indent += "  ";
            up += indent+"arr["+i+"] = "+arr+"["+ind+"];\n";
        }
        var body = "var res=[],\n    arr=[];\n"+up+indent+"res.push(arr.slice());\n"+down+"return res;";
        return cartesian.cache[n] = new Function(args, body);
    }
    
    0 讨论(0)
  • 2020-11-22 04:46

    After doing a little research I discovered a previous related question: Finding All Combinations of JavaScript array values

    I've adapted some of the code from there so that it returns an array of arrays containing all of the permutations:

    function(arraysToCombine) {
        var divisors = [];
        for (var i = arraysToCombine.length - 1; i >= 0; i--) {
           divisors[i] = divisors[i + 1] ? divisors[i + 1] * arraysToCombine[i + 1].length : 1;
        }
    
        function getPermutation(n, arraysToCombine) {
           var result = [], 
               curArray;    
           for (var i = 0; i < arraysToCombine.length; i++) {
              curArray = arraysToCombine[i];
              result.push(curArray[Math.floor(n / divisors[i]) % curArray.length]);
           }    
           return result;
        }
    
        var numPerms = arraysToCombine[0].length;
        for(var i = 1; i < arraysToCombine.length; i++) {
            numPerms *= arraysToCombine[i].length;
        }
    
        var combinations = [];
        for(var i = 0; i < numPerms; i++) {
            combinations.push(getPermutation(i, arraysToCombine));
        }
        return combinations;
    }
    

    I've put a working copy at http://jsfiddle.net/7EakX/ that takes the array you gave earlier ([[0,1], [0,1,2,3], [0,1,2]]) and outputs the result to the browser console.

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

    const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
    console.log(charSet.reduce((a,b)=>a.flatMap(x=>b.map(y=>x+y)),['']))

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

    You could take an iterative approach by building sub arrays.

    var parts = [[0, 1], [0, 1, 2, 3], [0, 1, 2]],
        result = parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
    
    console.log(result.map(a => a.join(', ')));
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    0 讨论(0)
提交回复
热议问题