www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using return type of a predicate function as a template

reply "Edwin van Leeuwen" <edder tkwsping.nl> writes:
I am trying to implement a groupBy function that groups by the 
return type of a predicate. Currently I have to define the 
returntype of the predicate for it to compile. Is there a way to 
get the return type at compile time and use it.

The code:
V[K] groupBy( alias func, K, V )( V values )
{
   V[K] grouped;
   foreach ( value ; values ) {
     grouped[func( value )] ~= value;
   }
   return grouped;
}

unittest {
   struct Test {
     string a;
     double b;
   }

   auto values = [Test( "a", 1 ), Test( "a", 2 ), Test( "b", 3 )];
   auto grouped = values.groupBy!( (a) => a.a, string );
   assert( grouped["a"].length == 2 );
   assert( grouped["a"][1].b == 2 );
   assert( grouped["b"].length == 1 );
   assert( grouped["b"][0].b == 3 );
}

So the above works, but I need to call it with:
values.groupBy!( (a) => a.a, string );
Ideally I would call it instead with:
values.groupBy!( (a) => a.a )
and it would infer that the template K needs to be a string, 
since that is the return type of (a) => a.a.

Cheers,

Edwin
Oct 16 2014
parent reply "Atila Neves" <atila.neves gmail.com> writes:
This works:

import std.range;

auto groupBy(alias func, R)(R values)
     if (isInputRange!R)
{

     alias K = typeof(func(values.front));
     alias V = ElementType!R[];
     V[K] grouped;
     foreach(value; values) grouped[func(value)] ~= value;
     return grouped;
}


unittest {
   struct Test {
     string a;
     double b;
   }

   auto values = [Test( "a", 1 ), Test( "a", 2 ), Test( "b", 3 )];
   auto grouped = values.groupBy!(a => a.a);
   assert( grouped["a"].length == 2 );
   assert( grouped["a"][1].b == 2 );
   assert( grouped["b"].length == 1 );
   assert( grouped["b"][0].b == 3 );
}

Atila

On Thursday, 16 October 2014 at 08:04:08 UTC, Edwin van Leeuwen 
wrote:
 I am trying to implement a groupBy function that groups by the 
 return type of a predicate. Currently I have to define the 
 returntype of the predicate for it to compile. Is there a way 
 to get the return type at compile time and use it.

 The code:
 V[K] groupBy( alias func, K, V )( V values )
 {
   V[K] grouped;
   foreach ( value ; values ) {
     grouped[func( value )] ~= value;
   }
   return grouped;
 }

 unittest {
   struct Test {
     string a;
     double b;
   }

   auto values = [Test( "a", 1 ), Test( "a", 2 ), Test( "b", 3 
 )];
   auto grouped = values.groupBy!( (a) => a.a, string );
   assert( grouped["a"].length == 2 );
   assert( grouped["a"][1].b == 2 );
   assert( grouped["b"].length == 1 );
   assert( grouped["b"][0].b == 3 );
 }

 So the above works, but I need to call it with:
 values.groupBy!( (a) => a.a, string );
 Ideally I would call it instead with:
 values.groupBy!( (a) => a.a )
 and it would infer that the template K needs to be a string, 
 since that is the return type of (a) => a.a.

 Cheers,

 Edwin
Oct 16 2014
parent "Edwin van Leeuwen" <edder tkwsping.nl> writes:
On Thursday, 16 October 2014 at 08:18:02 UTC, Atila Neves wrote:
 This works:

 import std.range;

 auto groupBy(alias func, R)(R values)
     if (isInputRange!R)
 {

     alias K = typeof(func(values.front));
     alias V = ElementType!R[];
     V[K] grouped;
     foreach(value; values) grouped[func(value)] ~= value;
     return grouped;
 }
Thank you, that is surprisingly straightforward :) Edwin
Oct 16 2014