7

I have 2 arrays that I want a Cartesian product of. As an example:

Customer Array:

[10,A]
[11,B]

Debtor Array:

[88,W]
[99,X]

I want to produce a new customerDebtor array with:

[10,A,88,W]
[10,A,99,X]
[11,B,88,W]
[11,B,99,X]

I am attempting it with this code:

for (var i = 0; i < customerArray.length; i++) {
    for (var l = 0; l < debtorArray.length; l++) {
        $.each(customerArray[i], function (ndx, val) {
            //???? push values into customerDebtorMatrix array
        });
    }
}
Ry-
  • 218,210
  • 55
  • 464
  • 476
Greg
  • 2,654
  • 3
  • 36
  • 59

4 Answers4

3

You don't need jquery for this:

var customerArray = [[10,'A'],[11,'B']];
var debtorArray = [[88,'W'],[99,'X']];

var customerDebtorMatrix = [];
for (var i = 0; i < customerArray.length; i++) {
    for (var l = 0; l < debtorArray.length; l++) {
        customerDebtorMatrix.push(customerArray[i].concat(debtorArray[l]));
    }
}

customerDebtorMatrix will be

[ [ 10, 'A', 88, 'W' ],
  [ 10, 'A', 99, 'X' ],
  [ 11, 'B', 88, 'W' ],
  [ 11, 'B', 99, 'X' ] ]
SheetJS
  • 22,470
  • 12
  • 65
  • 75
  • OK - I hear you. But, if I wanted to do it with jquery, what would that look like? – Greg Sep 29 '13 at 17:25
  • 2
    @Greg: Why would you want to do it with jQuery? You could use `$.each` instead of `for` loops. But there’s also `Array.prototype.forEach` for any reasonably modern browser in the first place… – Ry- Sep 29 '13 at 17:26
  • @Greg you'd need to have a nested `$.each`. It would look like `$.each(customerArray, function(k1,v1) { $.each(debtorArray, function(k2,v2) { customerDebtorMatrix.push(v1.concat(v2)); }); });` – SheetJS Sep 29 '13 at 17:28
  • Thanks Nirk - looks like the javascript syntax is much nicer (for a c# user).Thanks – Greg Sep 29 '13 at 17:29
3

concatMap works well here:

(function() {
    'use strict';

    // cartProd :: [a] -> [b] -> [[a, b]]
    function cartProd(xs, ys) {
        return [].concat.apply([], xs.map(function (x) {
            return [].concat.apply([], ys.map(function (y) {
                return [[x, y]];
            }));
        }));
    }

    return cartProd(["alpha", "beta", "gamma"], [1, 2, 3]);

})(); 

Returning:

[["alpha", 1], ["alpha", 2], ["alpha", 3], ["beta", 1], ["beta", 2], ["beta", 3], ["gamma", 1], ["gamma", 2], ["gamma", 3]]
1

2017 version

Using you data:

// Customer Array:
let c = [[10, 'A'], [11, 'B']];
// Debtor Array:
let d = [[88, 'W'], [99, 'X']];

all you need is one line:

let r = [].concat(...c.map(c => (d.map(d => c.concat(d)))));

or this for compatibility with older browsers that don't support the spread syntax:

let r = [].concat.apply([], c.map(c => (d.map(d => c.concat(d)))));

You can see that console.log(r); prints:

[ [ 10, 'A', 88, 'W' ],
  [ 10, 'A', 99, 'X' ],
  [ 11, 'B', 88, 'W' ],
  [ 11, 'B', 99, 'X' ] ]

which is exactly what you wanted.

No loops, no pushes to arrays, no jQuery, just a few simple function calls.

For more than two arrays, see this answer:

Community
  • 1
  • 1
rsp
  • 107,747
  • 29
  • 201
  • 177
0

Actually this would be the Kronecker (or Tensor) Product

Javascript code for the kronecker product of 2 arrays

function kronecker_product(a, b) 
{
    var i, j, k, al = a.length, bl = b.length, abl = al*bl, ab = new Array(abl);
    i = 0; j = 0;
    for (k=0; k<abl; k++)
    {
        if ( j>=bl) {j=0; i++;}
        ab[k] = [].concat(a[i],b[j]);
        j++;
    }
    return ab;
}

For disambiguation let me give the code for the cartesian product as well:

function cartesian_product(a, b) 
{
    var al = a.length, bl = b.length;
    return [a.concat(bl>al ? new Array(bl-al) : []), b.concat(al>bl ? new Array(al-bl) : [])];
}

The main difference is the number of components (length) of the final result, in kronecker the length should be the product of the lengths while in cartesian it should be the sum.

Example Kronecker

var a = ["a","b"], b = ["c","d"];
console.log(kronecker_product(a,b));

Output

[["a", "c"], ["a", "d"], ["b", "c"], ["b", "d"]]

Example Cartesian

var a = ["a","b"], b = ["c","d"];
console.log(cartesian_product(a,b));

Output

 [["a", "b"], ["c", "d"]]
Nikos M.
  • 8,033
  • 4
  • 36
  • 43