/* streaming cartesian product elements uses less memory ... */ const generator = cartesianProductSimplified(['a', 'b'], [1, 2, 3, 4], ['x', 'y', 'z']); /* prints [ 'a', 1, 'x' ] [ 'a', 1, 'y' ] [ 'a', 1, 'z' ] [ 'a', 2, 'x' ] [ 'a', 2, 'y' ] [ 'a', 2, 'z' ] [ 'a', 3, 'x' ] [ 'a', 3, 'y' ] [ 'a', 3, 'z' ] [ 'a', 4, 'x' ] [ 'a', 4, 'y' ] [ 'a', 4, 'z' ] [ 'b', 1, 'x' ] [ 'b', 1, 'y' ] [ 'b', 1, 'z' ] [ 'b', 2, 'x' ] [ 'b', 2, 'y' ] [ 'b', 2, 'z' ] [ 'b', 3, 'x' ] [ 'b', 3, 'y' ] [ 'b', 3, 'z' ] [ 'b', 4, 'x' ] [ 'b', 4, 'y' ] [ 'b', 4, 'z' ] */ printValues(generator); // helper function to print all values from a generator function function printValues(generator) { let iteration = null; while (iteration = generator.next()) { if (iteration.done === true) { break; } console.log(iteration.value); } } // helper function to construct the arguments array for the 'cartesianProduct' class function cartesianProductSimplified(...arrays) { let args = []; for (let i = 1; i < arrays.length; i++) { args = args.concat([cartesianProduct, arrays[i]]); } args.splice(0, 0, arrays[0]); return cartesianProduct(...args); } /* call it like this: cartesianProduct(['a', 'b'], cartesianProduct, [1, 2, 3, 4], cartesianProduct, ['x', 'y', 'z']); use cartesianProductSimplified to simplify it: cartesianProductSimplified(['a', 'b'], [1, 2, 3, 4], ['x', 'y', 'z']) */ function* cartesianProduct(values, generator, ...generatorArgs) { for (const value of values) { if (generator) { const iterator = generator(...generatorArgs); let iteration = null; while (iteration = iterator.next()) { if (iteration.done === true) { break; } yield [value, ...iteration.value]; } } else { yield [value]; } } }