I'm trying to use Linq expressions to construct a query, and am stuck trying to group by multiple columns. Say I have a basic collection:
IEnumerable<Row> collection = new Row[]
{
new Row() { Col1 = "a", Col2="x" },
new Row() { Col1 = "a", Col2="x" },
new Row() { Col1 = "a", Col2="y" },
};
I know you can group these using lambda expressions:
foreach (var grp in collection.GroupBy(item => new { item.Col1, item.Col2 }))
{
Debug.Write("Grouping by " + grp.Key.Col1 + " and " + grp.Key.Col2 + ": ");
Debug.WriteLine(grp.Count() + " rows");
}
This groups correctly as you can see:
Grouping by a and x: 2 rows
Grouping by a and y: 1 rows
But now, say I receive a collection of selectors to group against, that is passed to me as a parameter in my method, and that the entity type is generic:
void doLinq<T>(params Expression<Func<T,object>>[] selectors)
{
// linq stuff
}
Whoever's invoking the method would call like this:
doLinq<Row>(entity=>entity.Col1, entity=>entity.Col2);
How would I construct the group-by expression?
foreach (var grp in collection.GroupBy(
item => new {
// selectors??
}))
{
// grp.Key. ??
}
Edit
I updated above to hopefully clarify why I need the set of selectors.
Edit #2
Made the entity type in doLinq generic.
Well, I'll assume you use linq-to-sql or something similar, so you need expression trees. If not there might be other possibilities.
Possible solutions I can see:
see Vladimir Perevalovs answer.
see http://msdn.microsoft.com/en-us/library/bb882637.aspx
Well, that's my departement :)
untested code:
void doLinq(params string[] selectors) // checking two expressions for equality is messy, so I used strings
foreach (var grp in collection.GroupBy(
item => new {
Col1 = (selectors.Contains("Col1") ? item.Col1 : String.Empty),
Col2 = (selectors.Contains("Col2") ? item.Col2 : String.Empty)
// need to add a line for each column :(
}))
{
string[] grouping = (new string[]{grp.Key.Col1, grp.Key.Col2 /*, ...*/ }).Where(s=>!s.IsNullOrEmpty()).ToArray();
Debug.Write("Grouping by " + String.Join(" and ", grouping)+ ": ");
Debug.WriteLine(grp.Count() + " rows");
}
}
You should look at Dynamic Linq: http://blogs.msdn.com/b/mitsu/archive/2008/02/07/linq-groupbymany-dynamically.aspx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With