Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate all partitions, defined by one array, with elements of another array

I am trying to find all the partitions of the elements of an array, but with an important variation:

Each value of the second array needs to be spread out over the values of the first. So all values of the second array are always used.

Given these two arrays:

left = [A, B];
right = [1, 2, 3];

I expect a collection of the following results:

A = [1, 2, 3]
B = []

A = [1, 2]
B = [3]

A = [1, 3]
B = [2]

A = [2, 3]
B = [1]

A = [1]
B = [2, 3]

A = [2]
B = [1, 3]

A = [3]
B = [1, 2]

A = []
B = [1, 2, 3]

Edit:

So just to be clear. This needs to scale for both arrays.

Given arrays:

left = [A, B, C, D]
right = [1, 2, 3, 4, 5, 6]

Some of the (many, many possible) results would be:

A = [2, 5]
B = [1]
C = []
D = [3, 4, 6]

A = [6]
B = []
C = [1, 2, 3, 4, 5]
D = []

etc. etc. etc.
like image 840
SaphuA Avatar asked Jul 29 '15 13:07

SaphuA


1 Answers

Solution for any parameter (as long as the result is countable):

Edit: This version avoids possible problems with len = Math.pow(left.length, right.length) and problems with length over 36 (cnr!).

Example:

combine(['A', 'B'], [1, 2, 3]) all possible rows are 2^3 = 8. In this example, the distribution is binary, but it changes the base with more parameters of left.

  distribution      included in set
i       c            A           B   
----------------------------------------
0     0 0 0     { 1, 2, 3 } {         }
1     0 0 1     { 1, 2    } {       3 }
2     0 1 0     { 1,    3 } {    2    }
3     0 1 1     { 1       } {    2, 3 }
4     1 0 0     {    2, 3 } { 1       }
5     1 0 1     {    2    } { 1,    3 }
6     1 1 0     {       3 } { 1, 2    }
7     1 1 1     {         } { 1, 2, 3 }

The distribution i = 3 of 0 1 1 evaluates as:

  1. Take the first 0 and take it as index of left left[0] = A and move the place value of 0 of right right[0] = 1 to set A.
  2. Take the second 1 and take it as index of left left[1] = B and move the place value of 1 of right right[1] = 2 to set B.
  3. Take the third 1 and take it as index of left left[1] = B and move the place value of 2 of right right[2] = 3 to set B.

Another example:

combine(['A', 'B', 'C'], [1, 2]) all possible rows are 3^2 = 9.

  distribution     included in set
i      c          A        B       C
----------------------------------------
0     0 0     { 1, 2 } {      } {      }
1     0 1     { 1    } {    2 } {      }
2     0 2     { 1    } {      } {    2 }
3     1 0     {    2 } { 1    } {      }
4     1 1     {      } { 1, 2 } {      }
5     1 2     {      } { 1    } {    2 }
6     2 0     {    2 } {      } { 1    }
7     2 1     {      } {    2 } { 1    }
8     2 2     {      } {      } { 1, 2 }

function combine(left, right) {

    function carry() {
        return c.reduceRight(function (r, _, i, o) {
            return r && !(o[i] = (o[i] + 1) % left.length);
        }, 1);
    }

    var c = Array.apply(null, { length: right.length }).map(function () { return 0; }),
        result = [];

    do {
        result.push(c.reduce(function (r, a, i) {
            r[left[a]].push(right[i]);
            return r;
        }, left.reduce(function (r, a) {
            r[a] = [];
            return r;
        }, {})));
    } while (!carry());
    return result;
}
document.getElementById('out').innerHTML = 
    "combine(['A', 'B'], [1, 2, 3]) = " + JSON.stringify(combine(['A', 'B'], [1, 2, 3]), null, 4) + '\n'+
    "combine(['A', 'B', 'C'], [1, 2] = " + JSON.stringify(combine(['A', 'B', 'C'], [1, 2]), null, 4) +'\n'+
    "combine(['A', 'B', 'C'], [1, 2, 3] = " + JSON.stringify(combine(['A', 'B', 'C'], [1, 2, 3]), null, 4) +'\n'+
    "combine(['A', 'B', 'C', 'D'], [1, 2, 3, 4, 5, 6]) = " + JSON.stringify(combine(['A', 'B', 'C', 'D'], [1, 2, 3, 4, 5, 6]), null, 4);
<pre id="out"></pre>
like image 104
Nina Scholz Avatar answered Sep 23 '22 13:09

Nina Scholz