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 import std.algorithm.comparison : equal; 47 auto x = cartesianProductDynamic([["2", "3"], 48 ["green", "red"], 49 ["apples", "pears"]]); 50 assert(equal(x, 51 [["2", "green", "apples"], 52 ["2", "green", "pears"], 53 ["2", "red", "apples"], 54 ["2", "red", "pears"], 55 ["3", "green", "apples"], 56 ["3", "green", "pears"], 57 ["3", "red", "apples"], 58 ["3", "red", "pears"]])); 59 }