Linq GroupBy - how to specify a grouping key at runtime?

Is there a good way to make Linq GroupBy where the grouping key is determined at runtime? for example, I want a grouping key to be created from a list of fields selected by the user - can you do this? I know I can do this easily if I convert everything to a table of rows, but I was wondering if there is an elegant or smart way to do this otherwise.

 class Item { public int A, B; public DateTime D; public double X, Y, Z; } 

I have a List<Item> called data . I want to do things like get the sum of X , grouped by A , or the sums of X , Y and Z , grouped by A and B but which fields are included in the grouping must be specified at run time in some way.

+3
source share
2 answers

Get Dynamic LINQ and use the extension from which you can specify keySelector with a string.

 var query = db.Foo.GroupBy( "{0}", "GroupedProperty", groupKey ); 

You may also want to add your own extension if you want to return the entire object grouped by key.

 public static IQueryable GroupByComplete( this IQueryable source, string keySelector, params object[] values ) { if (source == null) throw new ArgumentNullException( "source" ); if (keySelector == null) throw new ArgumentNullException( "keySelector" ); LambdaExpression keyLambda = DynamicExpression.ParseLambda( source.ElementType, null, keySelector, values ); return source.Provider.CreateQuery( Expression.Call( typeof( Queryable ), "GroupBy", new Type[] { source.ElementType, keyLambda.Body.Type }, source.Expression, Expression.Quote( keyLambda ) ) ); } 
+5
source

All you need to do is build Func <Item, TKey> at runtime:

 var arg = Expression.Parameter(typeof(Item), "item"); var body = Expression.Property(arg, "D"); var lambda = Expression.Lambda<Func<Item, DateTime>>(body, arg); var keySelector = lambda.Compile(); 

Using:

 var result = source.GroupBy(keySelector); 

It gets a little (but not much) more complicated if you don't know the type of the property at compile time.

+8
source

All Articles