LINQ GroupBy child of a child

I am not sure if this question is a duplicate or not as this is something that I struggled a lot to search for as basically I don't know what would be the functionality name. So if that's the case my apologies.

Take an example where a team has persons and the person has several phone numbers, I would like to group by Number and still maintain all the information related with the team. So basically make the property Number the key of my groupby.

public class PhoneNumber
{
   public string Number { get; set; }
}

public class Person
{
  public List<PhoneNumber> PhoneNumbers { get; set; }
}

public class Team
{
  public List<Person> Persons{ get; set; }
}

IEnumerable<Team> teams = new List<Team>();

So I would like to do something similar to:

Team.Persons.GroupBy(i=> i.PhoneNumbers.Number)

which obviously I can't because PhoneNumbers is a List

The end result should be something like

  • Number1234 -> Team1, Team2
  • Number5678 -> Team1, Team2, Team3

Where NumberX is the groupby key and TeamX contains the information associated with a team that has a member with that phone number.

It might be that my approach is entirely out of place on this example so any feedback would be appreciated.

Jon Skeet
people
quotationmark

You basically need to flatten the results so you've got team/number pairs and then you can group by the number. So for example:

// IEnumerable<IGrouping<string, Team>>
var grouped = from team in teams
              from person in team.Persons
              from number in person.PhoneNumbers
              group team by number.Number;

You might also want to consider creating a Lookup instead of grouping:

// ILookup<string, Team>
var lookup = (from team in teams
              from person in team.Persons
              from number in person.PhoneNumbers
              select new { team, number }).ToLookup(p => p.number.Number,
                                                    p => p.team);

With the lookup, you can just do things like:

var number = "...";
foreach (var team in lookup[number])
{
    ...
}

... and it will helpfully return an empty sequence if you ask for the teams with an unknown phone number.

people

See more on this question at Stackoverflow