I need to group items in a list and then pass each group to a function for further elaboration. This is my code:
var list = new List<MyObj>(); // list is created ad populated elsewhere in code...
var query = list.AsEnumerable();
query = query.Where(x => x.MyProp == true).Select(x => x); // query definition is way more complicated
var grp = query.GroupBy(x => new { x.Name, x.Surname }).ToList();
Here grp
is of type List<IGrouping<'a, MyObj>>
.
I can easily iterate through my items with:
foreach (var g in grp)
{
foreach (var o in g)
{
// here "o" is of type MyObj
}
}
but I don't know how to create a function that receives a group and iterates through its items:
foreach (var g in grp)
{
DoSomethingWithGroup(g);
}
This is because I have an anonymous type (Key) in grp definition.
I tried to replace the Key anonymous type with a custom type:
private class GrpKey
{
public string Name { get; set; }
public string Surname { get; set; }
}
/* ... */
var grp = query.GroupBy(x => new GrpKey { Name = x.Name, Surname = x.Surname }).ToList();
This way grp is of type List<IGrouping<MyGrpKey, MyObj>>
instead of List<IGrouping<'a, MyObj>>
.
I could then create a function:
private void DoSomethingWithGroup(IGrouping<MyGrpKey, MyObj>) { /* ... */ }
Unfortunately, this way grouping doesn't work anymore: grp now contains as many groups as items in the source list, each one with a single item.
CodePudding user response:
Instead of specifying your method like you did:
private void DoSomethingWithGroup(IGrouping<MyGrpKey, MyObj>)
separate the key and the elements into their on parameters
private void DoSomethingWithGroup<T>(T groupKey, IEnumerable<MyObj> entities)
With this change you can do the following:
//Populate list with some dummy data
var list = new List<MyObj>()
{
new MyObj { Id = 1, MyProp = true, Name = "A", Surname = "B"},
new MyObj { Id = 2, MyProp = false, Name = "A", Surname = "B"},
new MyObj { Id = 3, MyProp = true, Name = "B", Surname = "B"},
new MyObj { Id = 4, MyProp = true, Name = "B", Surname = "B"},
new MyObj { Id = 5, MyProp = true, Name = "C", Surname = "B"},
};
//Perform the grouping
var groups = list
.Where(x => x.MyProp)
.GroupBy(x => new { x.Name, x.Surname })
.ToList();
//Perform some arbitrary action on the group basis
foreach (var group in groups)
{
DoSomethingWithGroup(group.Key, group);
}
If the implementation of the DoSomethignWithGroup
looks like this:
void DoSomethingWithGroup<T>(T groupKey, IEnumerable<MyObj> entities)
{
Console.WriteLine(groupKey);
foreach (var entity in entities)
{
Console.WriteLine($"- {entity.Id}");
}
}
then the output will be this:
{ Name = A, Surname = B }
- 1
{ Name = B, Surname = B }
- 3
- 4
{ Name = C, Surname = B }
- 5
CodePudding user response:
If the key is not needed in your function, you can omit that in the method. A IGrouping<TKey, TElement>
is an IEnumerable<TElement>
so you could just define it as:
private void DoSomethingWithGroup(IEnumerable<MyObj> items)
{
///...
}