www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.algorithm.reduce on an array of structs

reply "Colin" <grogan.colin gmail.com> writes:
I have this test code:

struct Thing {
     uint x;
}

void main(){
     uint[] ar1 = [1, 2, 3, 4, 5];
     auto min1 = ar1.reduce!((a,b) => a < b);
     writefln("%s", min1);  // prints 1 as expected

     Thing[] ar2 = [Thing(1), Thing(2), Thing(4)];
     auto min2 = ar2.reduce!((a,b) => a.x < b.x);  //  <- Wont 
Compile
     writefln("%s", min2);
}

The line with "Wont Compile" on it has this error message:
/usr/include/dmd/phobos/std/algorithm.d(770): Error: cannot 
implicitly convert expression (__lambda2(result, 
front(_param_1))) of type bool to Thing
/usr/include/dmd/phobos/std/algorithm.d(791): Error: template 
instance t.main.reduce!((a, b) => a.x < b.x).reduce!(Thing, 
Thing[]) error instantiating
t.d(16):        instantiated from here: reduce!(Thing[])


Any idea what I'm doing wrong here?
To me, the operation on ar2 should be pretty much identical to 
ar1, except for the use of the struct.
Sep 11 2014
next sibling parent reply "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 11 September 2014 at 13:06:05 UTC, Colin wrote:
 I have this test code:

 struct Thing {
     uint x;
 }

 void main(){
     uint[] ar1 = [1, 2, 3, 4, 5];
     auto min1 = ar1.reduce!((a,b) => a < b);
     writefln("%s", min1);  // prints 1 as expected

     Thing[] ar2 = [Thing(1), Thing(2), Thing(4)];
     auto min2 = ar2.reduce!((a,b) => a.x < b.x);  //  <- Wont 
 Compile
     writefln("%s", min2);
 }

 The line with "Wont Compile" on it has this error message:
 /usr/include/dmd/phobos/std/algorithm.d(770): Error: cannot 
 implicitly convert expression (__lambda2(result, 
 front(_param_1))) of type bool to Thing
 /usr/include/dmd/phobos/std/algorithm.d(791): Error: template 
 instance t.main.reduce!((a, b) => a.x < b.x).reduce!(Thing, 
 Thing[]) error instantiating
 t.d(16):        instantiated from here: reduce!(Thing[])


 Any idea what I'm doing wrong here?
 To me, the operation on ar2 should be pretty much identical to 
 ar1, except for the use of the struct.
You are try to put uint to Thing. This is corect version: import std.stdio; import std.algorithm; struct Thing { uint x; } void main(){ uint[] ar1 = [1, 2, 3, 4, 5]; auto min1 = ar1.reduce!((a,b) => a < b); writefln("%s", min1); // prints 1 as expected Thing[] ar2 = [Thing(1), Thing(2), Thing(4)]; auto min2 = ar2.reduce!((a,b) => a.x < b.x ? a : b); // <- Wont Compile writefln("%s", min2); }
Sep 11 2014
parent reply "Colin" <grogan.colin gmail.com> writes:
On Thursday, 11 September 2014 at 13:27:39 UTC, Daniel Kozak 
wrote:
 On Thursday, 11 September 2014 at 13:06:05 UTC, Colin wrote:
 I have this test code:

 struct Thing {
    uint x;
 }

 void main(){
    uint[] ar1 = [1, 2, 3, 4, 5];
    auto min1 = ar1.reduce!((a,b) => a < b);
    writefln("%s", min1);  // prints 1 as expected

    Thing[] ar2 = [Thing(1), Thing(2), Thing(4)];
    auto min2 = ar2.reduce!((a,b) => a.x < b.x);  //  <- Wont 
 Compile
    writefln("%s", min2);
 }

 The line with "Wont Compile" on it has this error message:
 /usr/include/dmd/phobos/std/algorithm.d(770): Error: cannot 
 implicitly convert expression (__lambda2(result, 
 front(_param_1))) of type bool to Thing
 /usr/include/dmd/phobos/std/algorithm.d(791): Error: template 
 instance t.main.reduce!((a, b) => a.x < b.x).reduce!(Thing, 
 Thing[]) error instantiating
 t.d(16):        instantiated from here: reduce!(Thing[])


 Any idea what I'm doing wrong here?
 To me, the operation on ar2 should be pretty much identical to 
 ar1, except for the use of the struct.
You are try to put uint to Thing. This is corect version: import std.stdio; import std.algorithm; struct Thing { uint x; } void main(){ uint[] ar1 = [1, 2, 3, 4, 5]; auto min1 = ar1.reduce!((a,b) => a < b); writefln("%s", min1); // prints 1 as expected Thing[] ar2 = [Thing(1), Thing(2), Thing(4)]; auto min2 = ar2.reduce!((a,b) => a.x < b.x ? a : b); // <- Wont Compile writefln("%s", min2); }
Ah ok. I get it. Thanks daniel!
Sep 11 2014
parent reply "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 11 September 2014 at 14:18:31 UTC, Colin wrote:
 Ah ok. I get it.

 Thanks daniel!
a quiet better version: import std.stdio; import std.algorithm; struct Thing { uint x; alias x this; } void main(){ uint[] ar1 = [1, 2, 3, 4, 5]; auto min1 = ar1.reduce!((a,b) => min(a,b)); writefln("%s", min1); Thing[] ar2 = [Thing(1), Thing(2), Thing(4)]; auto min2 = ar2.reduce!((a,b) => min(a,b)); writefln("%s", min2); }
Sep 11 2014
next sibling parent "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 11 September 2014 at 14:39:53 UTC, Daniel Kozak 
wrote:
 On Thursday, 11 September 2014 at 14:18:31 UTC, Colin wrote:
 Ah ok. I get it.

 Thanks daniel!
a quiet better version: import std.stdio; import std.algorithm; struct Thing { uint x; alias x this; } void main(){ uint[] ar1 = [1, 2, 3, 4, 5]; auto min1 = ar1.reduce!((a,b) => min(a,b)); writefln("%s", min1); Thing[] ar2 = [Thing(1), Thing(2), Thing(4)]; auto min2 = ar2.reduce!((a,b) => min(a,b)); writefln("%s", min2); }
s/quiet/quite/
Sep 11 2014
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Daniel Kozak:

You can just use min:

import std.stdio, std.algorithm;

struct Thing {
     uint x;
     alias x this;
}

alias minimum = reduce!min;

void main() {
	immutable ar1 = [10, 20, 30, 40, 50];
	ar1.minimum.writeln;

	immutable ar2 = [Thing(10), Thing(20), Thing(40)];
	ar2.minimum.writeln;
}

Bye,
bearophile
Sep 11 2014
next sibling parent reply Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
V Thu, 11 Sep 2014 14:49:02 +0000
bearophile via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
napsáno:

 Daniel Kozak:
 
 You can just use min:
 
 import std.stdio, std.algorithm;
 
 struct Thing {
      uint x;
      alias x this;
 }
 
 alias minimum = reduce!min;
 
 void main() {
 	immutable ar1 = [10, 20, 30, 40, 50];
 	ar1.minimum.writeln;
 
 	immutable ar2 = [Thing(10), Thing(20), Thing(40)];
 	ar2.minimum.writeln;
 }
 
 Bye,
 bearophile
Yep, this look the most idiomatic :). Why there is no phobos function for minimum of array(range)?
Sep 11 2014
next sibling parent reply "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 11 September 2014 at 14:56:00 UTC, Daniel Kozak via 
Digitalmars-d-learn wrote:
 V Thu, 11 Sep 2014 14:49:02 +0000
 bearophile via Digitalmars-d-learn 
 <digitalmars-d-learn puremagic.com>
 napsáno:

 Daniel Kozak:
 
 You can just use min:
 
 import std.stdio, std.algorithm;
 
 struct Thing {
      uint x;
      alias x this;
 }
 
 alias minimum = reduce!min;
 
 void main() {
 	immutable ar1 = [10, 20, 30, 40, 50];
 	ar1.minimum.writeln;
 
 	immutable ar2 = [Thing(10), Thing(20), Thing(40)];
 	ar2.minimum.writeln;
 }
 
 Bye,
 bearophile
Yep, this look the most idiomatic :). Why there is no phobos function for minimum of array(range)?
or use alias minimum = reduce!"a < b"; ;)
Sep 11 2014
parent reply "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 11 September 2014 at 15:07:03 UTC, Daniel Kozak 
wrote:
 or use alias minimum = reduce!"a < b";
 ;)
ok this one does not work
Sep 11 2014
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 11 September 2014 at 15:29:18 UTC, Daniel Kozak
wrote:
 On Thursday, 11 September 2014 at 15:07:03 UTC, Daniel Kozak 
 wrote:
 or use alias minimum = reduce!"a < b";
 ;)
ok this one does not work
Yeah, it's actually reduce!"a < b ? a : b"
Sep 11 2014
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 11 September 2014 at 14:56:00 UTC, Daniel Kozak via 
Digitalmars-d-learn wrote:
 V Thu, 11 Sep 2014 14:49:02 +0000
 bearophile via Digitalmars-d-learn 
 <digitalmars-d-learn puremagic.com>
 napsáno:

 Daniel Kozak:
 
 You can just use min:
 
 import std.stdio, std.algorithm;
 
 struct Thing {
      uint x;
      alias x this;
 }
 
 alias minimum = reduce!min;
 
 void main() {
 	immutable ar1 = [10, 20, 30, 40, 50];
 	ar1.minimum.writeln;
 
 	immutable ar2 = [Thing(10), Thing(20), Thing(40)];
 	ar2.minimum.writeln;
 }
 
 Bye,
 bearophile
Yep, this look the most idiomatic :). Why there is no phobos function for minimum of array(range)?
To note though: minPos will "find" the position of the smallest element, whereas reduce will accumulate and return the lowest value. That said: alias minmax = reduce!(min, max); auto mm = ar1.minmax(); auto min = mm[0]; auto max = mm[1]; Found both in one line of code, and only 1 iteration of ar1.
Sep 11 2014
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Thursday, 11 September 2014 at 14:49:03 UTC, bearophile wrote:
 void main() {
       //... 	

 	immutable ar2 = [Thing(10), Thing(20), Thing(40)];
 	ar2.minimum.writeln;
 }

 Bye,
 bearophile
Even better: void main { immutable(Thing)[] ar2 = [10, 20, 40]; ar2.minimum.writeln; }
Sep 11 2014
prev sibling parent reply "Colin" <grogan.colin gmail.com> writes:
On Thursday, 11 September 2014 at 14:49:03 UTC, bearophile wrote:
 Daniel Kozak:

 You can just use min:

 import std.stdio, std.algorithm;

 struct Thing {
     uint x;
     alias x this;
 }

 alias minimum = reduce!min;

 void main() {
 	immutable ar1 = [10, 20, 30, 40, 50];
 	ar1.minimum.writeln;

 	immutable ar2 = [Thing(10), Thing(20), Thing(40)];
 	ar2.minimum.writeln;
 }

 Bye,
 bearophile
Using the "alias x this" solution would work, but my actual struct is not a simple struct, so the comparison isn't exactly (a.x < b.x).
Sep 11 2014
parent "Meta" <jared771 gmail.com> writes:
On Thursday, 11 September 2014 at 21:28:59 UTC, Colin wrote:
 Using the "alias x this" solution would work, but my actual 
 struct is not a simple struct, so the comparison isn't exactly 
 (a.x < b.x).
You could always override opCmp as well: http://dlang.org/operatoroverloading.html#compare
Sep 11 2014
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Thursday, 11 September 2014 at 13:06:05 UTC, Colin wrote:
 I have this test code:

 struct Thing {
     uint x;
 }

 void main(){
     uint[] ar1 = [1, 2, 3, 4, 5];
     auto min1 = ar1.reduce!((a,b) => a < b);
     writefln("%s", min1);  // prints 1 as expected

     Thing[] ar2 = [Thing(1), Thing(2), Thing(4)];
     auto min2 = ar2.reduce!((a,b) => a.x < b.x);  //  <- Wont 
 Compile
     writefln("%s", min2);
 }

 The line with "Wont Compile" on it has this error message:
 /usr/include/dmd/phobos/std/algorithm.d(770): Error: cannot 
 implicitly convert expression (__lambda2(result, 
 front(_param_1))) of type bool to Thing
 /usr/include/dmd/phobos/std/algorithm.d(791): Error: template 
 instance t.main.reduce!((a, b) => a.x < b.x).reduce!(Thing, 
 Thing[]) error instantiating
 t.d(16):        instantiated from here: reduce!(Thing[])


 Any idea what I'm doing wrong here?
 To me, the operation on ar2 should be pretty much identical to 
 ar1, except for the use of the struct.
I think you want to use `filter()` (for both Thing and uint), not `reduce()`. The former produces a range with only the elements that match the predicate, while the latter produces _one_ element according to the given rules, e.g. my_int_array.reduce!((result,a) => result+a); produces the sum of all elements. In your example, the first use only compiles because `bool` happens to be implicitly convertible to `uint`.
Sep 11 2014
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Thursday, 11 September 2014 at 13:28:37 UTC, Marc Schütz wrote:
 On Thursday, 11 September 2014 at 13:06:05 UTC, Colin wrote:
 I have this test code:

 struct Thing {
    uint x;
 }

 void main(){
    uint[] ar1 = [1, 2, 3, 4, 5];
    auto min1 = ar1.reduce!((a,b) => a < b);
    writefln("%s", min1);  // prints 1 as expected

    Thing[] ar2 = [Thing(1), Thing(2), Thing(4)];
    auto min2 = ar2.reduce!((a,b) => a.x < b.x);  //  <- Wont 
 Compile
    writefln("%s", min2);
 }

 The line with "Wont Compile" on it has this error message:
 /usr/include/dmd/phobos/std/algorithm.d(770): Error: cannot 
 implicitly convert expression (__lambda2(result, 
 front(_param_1))) of type bool to Thing
 /usr/include/dmd/phobos/std/algorithm.d(791): Error: template 
 instance t.main.reduce!((a, b) => a.x < b.x).reduce!(Thing, 
 Thing[]) error instantiating
 t.d(16):        instantiated from here: reduce!(Thing[])


 Any idea what I'm doing wrong here?
 To me, the operation on ar2 should be pretty much identical to 
 ar1, except for the use of the struct.
I think you want to use `filter()` (for both Thing and uint), not `reduce()`.
Scratch that, `filter()` doesn't make sense here, of course. The rest is still valid:
 The former produces a range with only the elements that match 
 the predicate, while the latter produces _one_ element 
 according to the given rules, e.g.

     my_int_array.reduce!((result,a) => result+a);

 produces the sum of all elements. In your example, the first 
 use only compiles because `bool` happens to be implicitly 
 convertible to `uint`.
Sep 11 2014