1 module nxt.products;
2 
3 import std.range.primitives : isInputRange, ElementType;
4 
5 auto cartesianProductDynamic(R)(R x)
6     if (isInputRange!R &&
7         isInputRange!(ElementType!R))
8 {
9     import std.algorithm : map;
10     import std.algorithm.setops : cartesianProduct;
11     import std.array : array;
12     import std.algorithm : count;
13     import nxt.traits_ex : asDynamicArray;
14 
15     alias E = ElementType!(ElementType!R);
16     alias C = E[]; // combination
17     const n = x.count;
18 
19     final switch (n)
20     {
21     case 0: return R.init;
22     case 1: return [x[0]];
23     case 2: return cartesianProduct(x[0], x[1]).map!(a => a.asDynamicArray).array;
24     case 3: return cartesianProduct(x[0], x[1], x[2]).map!(a => a.asDynamicArray).array;
25     case 4: return cartesianProduct(x[0], x[1], x[2], x[3]).map!(a => a.asDynamicArray).array;
26     case 5: return cartesianProduct(x[0], x[1], x[2], x[3], x[4]).map!(a => a.asDynamicArray).array;
27     case 6: return cartesianProduct(x[0], x[1], x[2], x[3], x[4], x[5]).map!(a => a.asDynamicArray).array;
28     case 7: return cartesianProduct(x[0], x[1], x[2], x[3], x[4], x[5], x[6]).map!(a => a.asDynamicArray).array;
29     case 8: return cartesianProduct(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]).map!(a => a.asDynamicArray).array;
30     case 9: return cartesianProduct(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]).map!(a => a.asDynamicArray).array;
31     // default:
32     //     foreach (const i; 0 .. n)
33     //     {
34     //         foreach (const j; x[i])
35     //         {
36     //             y[i] ~= j;
37     //         }
38     //     }
39     //     auto y = new C[n];
40     //     return y;
41     }
42 
43 }
44 
45 unittest
46 {
47     import std.algorithm.comparison : equal;
48     auto x = cartesianProductDynamic([["2", "3"],
49                                       ["green", "red"],
50                                       ["apples", "pears"]]);
51     assert(equal(x,
52                  [["2", "green", "apples"],
53                  ["2", "green", "pears"],
54                   ["2", "red", "apples"],
55                   ["2", "red", "pears"],
56                   ["3", "green", "apples"],
57                   ["3", "green", "pears"],
58                   ["3", "red", "apples"],
59                   ["3", "red", "pears"]]));
60 }