GroupBy with multiple groups as a hierarchy
I am using GroupBy create a hierarchical set of groups to use in multiple child grids.
Assume I have a query with with 6 columns, a, b, c, d, e, f.
Now, I need to group by a, then by b, then by c. and return the entire row in the group of c's.
var q = rows.GroupBy(x => x.a)
Ok, that's nice. That gives me my group of a's. Next, we look to group them by a and b.
va开发者_运维技巧r q1 = q.Select(g =>new {
Key = g.Key,
SubGroup = g.GroupBy(x => x.b)
}
Ok, that also works nice. I get my group of a's with subgroups of b's.
Now I'm stumped at the third level. I've tried various syntaxes, but most won't even compile. The ones that do do not give the correct results.
var q2 = q1.Select(g1 => new {
Key = g1.Key,
SubGroup = g1.GroupBy(x => x.c)
}
This doesn't compile. Tells me that there is no GroupBy on g1.
var q2 = q.Select(g1 => new {
Key = g1.Key,
SubGroup = g1.GroupBy(x => x.c)
}
This doesn't give me the b subgroup, only the a and c.
Any idea of what i'm doing wrong here?
EDIT:
The Following also does not work, saying there is no definition for the g1.Key
var q2 = q.Select(g => new {
Key = g.Key,
SubGroup = g.Select(g1 => new {
Key = g1.Key
SubGroup = g1.GroupBy(a => a.c)
})
I have such a poor grasp on what this is doing internally.
Now, I'm not saying this is actually a good approach; it's probably going to be slow and the right way to do this, if performance matters, may be to sort the whole collection by these different criteria and then look at the different parts of the sorted collection.
But if you want to use GroupBy
and IGroupings
to manage it, you're working at it from the wrong end. You want to start at the deepest level first and work up.
var groups = rows
.GroupBy(x => new { x.A, x.B, x.C, x.D, x.E, x.F })
.GroupBy(x => new { x.Key.A, x.Key.B, x.Key.C, x.Key.D, x.Key.E })
.GroupBy(x => new { x.Key.A, x.Key.B, x.Key.C, x.Key.D, })
.GroupBy(x => new { x.Key.A, x.Key.B, x.Key.C })
.GroupBy(x => new { x.Key.A, x.Key.B })
.GroupBy(x => x.Key.A);
groups.First().Key; // will be an A value
groups.First().First().First(); // will be an A, B, C group
GroupBy actually supports giving a list of elements to group by. Each group will contain the same first 3 items (A, B & C). You can get the key with the .Key method, and play around with the different rows with foreach. See Example:
var groups = Elements.GroupBy(x => new {x.A, x.B, x.C});
foreach (var group in groups)
{
Trace.WriteLine(group.Key + ": " + group.Count());
foreach (var row in group)
{
Trace.WriteLine(row.D);
}
}
Edit: Ahh, ok - what you need is this then:
var groups = Elements
.GroupBy(a => new {a.A})
.Select(g1 => new {
A = g1.Key,
Groups = g1
.GroupBy(b=> new {b.B})
.Select(g2 => new {
B = g2.Key,
Groups = g2
.GroupBy(c => new {c.C})
.Select(g3 => new {
C = g3.Key,
Rows = g3
})
})
});
foreach (var groupA in groups)
{
Trace.WriteLine(groupA.A);
foreach (var groupB in groupA.Groups)
{
Trace.WriteLine("\t" + groupB.B);
foreach (var groupC in groupB.Groups)
{
Trace.WriteLine("\t\t" + groupC.C);
foreach (var row in groupC.Rows)
{
Trace.WriteLine("Row: " + row.ToString());
}
}
}
}
精彩评论