Permutation - JavaScript - Generating Combinations From n Arrays With m Elements - Stack Overflow

Embed Size (px)

DESCRIPTION

Upload

Citation preview

  • Take the 2-minute tour

    quano4,669 10 58 95

    4 Answers

    I'm having trouble coming up with code to generate combinations from n number of arrays with m number ofelements in them, in JavaScript. I've seen similar questions about this for other languages, but the answersincorporate syntactic or library magic that I'm unsure how to translate.

    Consider this data:

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

    3 arrays, with a different number of elements in them. What I want to do is get all combinations by combiningan item from each array.

    For example:

    0,0,0 // item 0 from array 0, item 0 from array 1, item 0 from array 20,0,10,0,20,1,00,1,10,1,20,2,00,2,10,2,2

    And so on.

    If the number of arrays were fixed, it would be easy to make a hard coded implementation. But the number ofarrays may vary:

    [[0,1], [0,1]][[0,1,3,4], [0,1], [0], [0,1]]

    Any help would be much appreciated.

    javascript permutation combinations

    asked Mar 8 '13 at 16:37

    See also possible duplicates: Finding All Combinations of JavaScript array values, cartesian product of multiplearrays in javascript, JavaScript Golf - Cartesian Product or similar Bergi Oct 1 '13 at 23:17

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

    function cartesian() { var r = [], arg = arguments, max = arg.length-1; function helper(arr, i) { for (var j=0, l=arg[i].length; j

  • Bergi82.6k 6 35 84

    Neob9170 7

    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(arg)so that arg is a parameter instead of all arguments .

    edited Mar 9 '13 at 11:49 answered Mar 9 '13 at 11:18

    Awesome, thanks. Benchmark is available here: jsfiddle.net/9uvfP . Your solution takes 0.14 seconds to run100,000 times, making it the fastest implementation submitted yet. :) quano Mar 9 '13 at 12:00

    Ah, I noticed an error in the benchmark. Updated here: jsfiddle.net/2xt5F . It takes about 0.6 seconds. quano Mar 9 '13 at 12:13

    This is similar to the approach I originally took, but couldn't get there... A bit sleep deprived from a new baby, butglad someone did it so I could see!! Tom Pietrosanti Mar 9 '13 at 14:00

    Looks like, I'm going to become your fan. You're genious. HAL9000 Mar 26 at 14:49

    var f = function(arr){ if(typeof arr !== 'object'){ return false; }

    arr = arr.filter(function(elem){ return (elem !== null); }); // remove empty elements - make 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;answered Mar 8 '13 at 18:01

    Thanks. Benchmark available here: jsfiddle.net/6cxEH . Your solution takes around 0.6 seconds to run 100,000times. quano Mar 9 '13 at 12:02

    I'm glad to help, and happy that it's efficient. ;) Neob91 Mar 10 '13 at 20:10

    After doing a little research I discovered a previous related question: Finding All Permuations of JavaScriptarray values

    permutation - JavaScript - Generating combinations from n ar... http://stackoverflow.com/questions/15298912/javascript-gener...

    2 of 4 07/04/14 12:43 PM

  • Neil688 2 6 19

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

    function(arraysToCombine) { var divisors = []; for (var i = arraysToCombine.length - 1; i >= 0; i--) { divisors[i] = divisors[i + 1] ? divisors[i + 1] * arraysToCombine[i + 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.

    answered Mar 8 '13 at 18:39

    Works great. I made a benchmark: jsfiddle.net/kLfq9 . Your solution takes about 0.5 seconds to run 100,000times in Chrome on my computer. quano Mar 9 '13 at 11:44

    Here's another way of doing it. I treat the indices of all of the arrays like a number whose digits are alldifferent 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. Thecounter starts 000, then goes 001, 002, then 010. The digits correspond to indices in the arrays, and sinceorder 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-- ){

    permutation - JavaScript - Generating combinations from n ar... http://stackoverflow.com/questions/15298912/javascript-gener...

    3 of 4 07/04/14 12:43 PM

  • Tom Pietrosanti2,154 1 5 15

    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 arraysconsole.log(combinations([[0,1], [0,1,2,3], [0,1,2]]));

    answered Mar 9 '13 at 7:03

    1 Thank you for the solution. Benchmark is available here: jsfiddle.net/XgyPC . It runs your function 100,000times. It takes about 1 second on my computer in Chrome. quano Mar 9 '13 at 11:45

    Excellent! Thank you for running the benchmark. I was wondering how it would perform, and hadn't put muchthought into that aspect. This is a fun little problem to solve, so I might give it another go. Tom PietrosantiMar 9 '13 at 13:57

    Not the answer you're looking for? Browse other questions tagged javascript

    permutation combinations or ask your own question.

    permutation - JavaScript - Generating combinations from n ar... http://stackoverflow.com/questions/15298912/javascript-gener...

    4 of 4 07/04/14 12:43 PM