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 }