Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GroupBy on list property → object in each group

Tags:

c#

linq

example structure is:

class Project {
    public string Name { get; set; }
}

class TeamMember {
    public string Email { get; set; }
    public List<Project> Projects { get; set; }
}

Is there a (simple) way to use GroupBy to get a group for every project with all the members as list?

When using foreach(var group in members.GroupBy(m => m.Projects.First().Name)) it's obviously only grouping by the first project for each member. But i want all possible projects with a list of all members.

The "simplest" solution I can think of is: (i'm running the project groups through a foreach loop anyway)

var projects = members.SelectMany(m => m.Projects).Select(p => p.Name).Distinct().ToList();
foreach (var proj in projects)
{
    var relevantMembers = members.Where(p => p.Projects.Select(pj => pj.Name).Contains(proj)).ToList();
    ...
}
like image 889
dnanon Avatar asked Jun 06 '18 13:06

dnanon


1 Answers

Here's one way to go about it:

 var result = 
     members.SelectMany(s => s.Projects.Select(x => (name: x.Name, obj: s)))
            .GroupBy(x => x.name)
            .ToDictionary(x => x.Key, x => x.Select(e => e.obj).ToList());

or if you're not using C#7 then you can use a Tuple for the intermediate projection:

var result = 
    members.SelectMany(s => s.Projects.Select(x => 
                            new Tuple<string, TeamMember>(x.Name, s)))
           .GroupBy(x => x.Item1)
           .ToDictionary(x => x.Key, x => x.Select(e => e.Item2).ToList());

result is now type Dictionary<string, List<TeamMember>>.

or as @René Vogt suggested you can simplify it further by using anonymous types:

var result = members.SelectMany(s => s.Projects.Select(x => new { x.Name, s }))
                    .GroupBy(x => x.Name)
                    .ToDictionary(x => x.Key, x => x.Select(e => e.s).ToList());
like image 171
Ousmane D. Avatar answered Sep 28 '22 16:09

Ousmane D.