www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - help on cartesianProduct()

reply Orut <orut fakeemailfornow.com> writes:
Am trying to port some Python code to D and I got stumped on the 
use of cartesianProduct() from std.algorithm.setops. In Python, 
the same functionality is implemented by product() in the 
itertools module. I need to be able to vary the number of ranges 
to feed into cartesianProduct() at run time. In Python, this is 
possible because I can dynamically construct a list of lists, 
then unpack this list using the unpacking operator when it is fed 
as argument to product(). In D, as far as I can tell (D nub 
here), I can't unpack arrays (no expand property), and I can't 
dynamically change the content of tuples (fixed at compile time). 
A possible hack is to create different versions of the function 
call (each with a fixed number of arguments), say cases under a 
switch, but this gets ugly if I anticipate a large number of 
possible scenarios. Would appreciate any idea. Thanks.
Dec 11 2016
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Sunday, 11 December 2016 at 16:34:38 UTC, Orut wrote:
 I need to be able to vary the number of ranges to feed into 
 cartesianProduct() at run time. In Python, this is possible 
 because I can dynamically construct a list of lists, then 
 unpack this list using the unpacking operator when it is fed as 
 argument to product()
Hmmm... what kind of ranges? Are they going to be arrays? Or something else? Could make your own cartesian function range that works the same way, doesn't seem too complicated on that...
Dec 11 2016
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Sunday, 11 December 2016 at 18:05:19 UTC, Era Scarecrow wrote:
 On Sunday, 11 December 2016 at 16:34:38 UTC, Orut wrote:
 I need to be able to vary the number of ranges to feed into 
 cartesianProduct() at run time.
Hmmm... what kind of ranges? Are they going to be arrays? Or something else?
Well, with the assumption of using arrays (since you kinda need a length for it to work) I've thrown together a quick struct that does the job. Not fully tested, but will do the same thing with a varying number of inputs. [code] struct MultiCart(T) { T[][] data; int iteration; int max; this(T[][] _d, int iter=0) { data = _d; iteration = iter; max = 1; foreach(a; _d) { if (a.length) max *= a.length; } } T[] front() { int i = iteration; T[] val; foreach(d; data) { if (d.length) { val ~= d[i % d.length]; i /= d.length; } } return val; } void popFront() { iteration++; } bool empty() { return iteration >= max; } } unittest { import std.stdio; alias CartInt = MultiCart!int; int[] a=[1,2,3],b=[4,5],c=[6,7]; foreach(x; CartInt([a,b,c])) writeln(x); foreach(x; CartInt([a,b])) writeln(x); } [/code]
Dec 11 2016
parent reply Orut <orut fakeemailfornow.com> writes:
On Sunday, 11 December 2016 at 23:07:16 UTC, Era Scarecrow wrote:
 On Sunday, 11 December 2016 at 18:05:19 UTC, Era Scarecrow 
 wrote:
 On Sunday, 11 December 2016 at 16:34:38 UTC, Orut wrote:
 I need to be able to vary the number of ranges to feed into 
 cartesianProduct() at run time.
Hmmm... what kind of ranges? Are they going to be arrays? Or something else?
Well, with the assumption of using arrays (since you kinda need a length for it to work) I've thrown together a quick struct that does the job. Not fully tested, but will do the same thing with a varying number of inputs. [code] struct MultiCart(T) { T[][] data; int iteration; int max; this(T[][] _d, int iter=0) { data = _d; iteration = iter; max = 1; foreach(a; _d) { if (a.length) max *= a.length; } } T[] front() { int i = iteration; T[] val; foreach(d; data) { if (d.length) { val ~= d[i % d.length]; i /= d.length; } } return val; } void popFront() { iteration++; } bool empty() { return iteration >= max; } } unittest { import std.stdio; alias CartInt = MultiCart!int; int[] a=[1,2,3],b=[4,5],c=[6,7]; foreach(x; CartInt([a,b,c])) writeln(x); foreach(x; CartInt([a,b])) writeln(x); } [/code]
The code works beautifully! Thank you very much. Will certainly acknowledge you as source of this code if this becomes of part of a bigger project. I hope others searching this forum would also discover this code.
Dec 12 2016
parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Monday, 12 December 2016 at 14:27:07 UTC, Orut wrote:
 The code works beautifully! Thank you very much. Will certainly 
 acknowledge you as source of this code if this becomes of part 
 of a bigger project. I hope others searching this forum would 
 also discover this code.
It could probably use some minor cleanup, documentation and proper unittests and constraints, moving to unsigned size_t; If front is used more than once than there's inefficiency with memory and remaking the array it builds (among other things). Could even make an opIndex for creating specific iterations of the results. But for it's simplicity I hope it does what you need. It really wasn't that hard to make.
Dec 12 2016