Search code examples
c#linq

How to access TElement of IEnumerable<IGrouping<TKey, TElement>> returned by GroupBy() in method call syntax


Using Linq's GroupBy() method, returns IEnumerable<IGrouping<TKey, TElement>> type.

At this time, I wnat to return an anonymous type that matches TElement to TKey using Select() in method call syntax.

Here's the data we use in this question.

public class Pet
{
  public string Name { get; set; }
  public int Age { get; set; }
}
List<Pet> pets = new List<Pet>
  { 
    new Pet { Name="Barley", Age=8 },
    new Pet { Name="Boots", Age=4 },
    new Pet { Name="Whiskers", Age=1 },
    new Pet { Name="Daisy", Age=4 } 
  };

I can acheive what I want by nesting foreach in the following methodCallSyntax.

var methodCallSyntax = pets.GroupBy(pet => pet.Age, pet => pet.Name);

foreach (var grouping in methodCallSyntax)
{
  foreach (var element in grouping)
  {
    Console.WriteLine($"Key: {grouping.Key}, Element: {element}");
  }
}

But I want to use foreach only once.

var methodCallSyntax =
  pets
    .GroupBy(pet => pet.Age, pet => pet.Name)
    // .Select(grouping => new {grouping.Key, Element = grouping.});

foreach (var item in methodCallSyntax)
{
  Console.WriteLine($"Key: {item.Key}, Element: {item.Element}");
}

But as you can see I don't know what to fill out Select().

How can I do this?


Solution

  • You can use SelectMany after GroupBy, and use a Select inside of SelectMany.

    SelectMany transforms a multi-dimensional collection into a single sequence. The inner Select will return a collection, and SelectMany will transform all those values from Select into a single collection.

    var all = pets
        .GroupBy(pet => pet.Age, pet => pet.Name)
        .SelectMany(group => group
            .Select(name => new { key = group.Key, value = name })
        );
    

    Usage

    foreach (var item in all)
    {
        Console.WriteLine($"Key: {item.key}, Element: {item.value}");
    }