There are other questions about this in other languages, and other non-lazy JavaScript versions, but no lazy JavaScript versions that I have found.
Given an array of an arbitrary number of arbitrary-sized arrays:
var sets = [ [2,3,4,5], ['sweet','ugly'], ['cats','dogs','hogs'] ];
and a callback function:
function holla( n, adj, noun ){
console.log( [n,adj,noun].join(' ') );
}
what's an elegant way to iterate the entire product space without creating a huge array of all possible combinations first?
lazyProduct( sets, holla );
// 2 sweet cats
// 2 sweet dogs
// 2 sweet hogs
// 2 ugly cats
// 2 ugly dogs
// 2 ugly hogs
// 3 sweet cats
// 3 sweet dogs
// 3 sweet hogs
// 3 ugly cats
// 3 ugly dogs
// 3 ugly hogs
// 4 sweet cats
// 4 sweet dogs
// 4 sweet hogs
// 4 ugly cats
// 4 ugly dogs
// 4 ugly hogs
// 5 sweet cats
// 5 sweet dogs
// 5 sweet hogs
// 5 ugly cats
// 5 ugly dogs
// 5 ugly hogs
Note that these combinations are the same as the results you would get if you had nested loops:
var counts = [2,3,4,5];
var adjectives = ['sweet','ugly'];
var animals = ['cats','dogs','hogs'];
for (var i=0;i<counts.length;++i){
for (var j=0;j<adjectives.length;++j){
for (var k=0;k<animals.length;++k){
console.log( [ counts[i], adjectives[j], animals[k] ].join(' ') );
}
}
}
The benefits of the Cartesian product are:
You can see the benchmarks for the answers below here:
http://jsperf.com/lazy-cartesian-product/26
A combination of recursion and iteration will do the job.
function lazyProduct(sets, holla) {
var setLength = sets.length;
function helper(array_current, set_index) {
if (++set_index >= setLength) {
holla.apply(null, array_current);
} else {
var array_next = sets[set_index];
for (var i=0; i<array_next.length; i++) {
helper(array_current.concat(array_next[i]), set_index);
}
}
}
helper([], -1);
}
var sets = [ [2,3,4,5], ['sweet','ugly'], ['cats','dogs','hogs'] ];
function holla( n, adj, noun ){
console.log( [n,adj,noun].join(' ') );
}
lazyProduct(sets,holla);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With