429
public class ConsolidatedChild
{
    public string School { get; set; }
    public string Friend { get; set; }
    public string FavoriteColor { get; set; }
    public List<Child> Children { get; set; }
}

public class Child
{
    public string School { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Friend { get; set; }
    public string Mother { get; set; }
    public string FavoriteColor { get; set; }
}

Given the two classes above, I would like to use LINQ to create a List from the List, grouped by the School, Friend and FavoriteColor properties. Is this possible with LINQ?

Please ignore the properties, the code has been written just to help with the question.

Kasy
  • 4,301
  • 2
  • 15
  • 6
  • 1
    Yes it is possible. Take a look at the sample provided in [this](http://weblogs.asp.net/zeeshanhirani/archive/2008/05/07/group-by-multiple-columns-in-linq-to-sql.aspx) post. – Kamyar Mar 08 '11 at 11:34
  • 2
    Here is another good example http://stackoverflow.com/questions/15605468/using-linq-to-group-by-multiple-properties-and-sum – NoWar Aug 29 '16 at 15:23

2 Answers2

712
var consolidatedChildren =
    from c in children
    group c by new
    {
        c.School,
        c.Friend,
        c.FavoriteColor,
    } into gcs
    select new ConsolidatedChild()
    {
        School = gcs.Key.School,
        Friend = gcs.Key.Friend,
        FavoriteColor = gcs.Key.FavoriteColor,
        Children = gcs.ToList(),
    };

var consolidatedChildren =
    children
        .GroupBy(c => new
        {
            c.School,
            c.Friend,
            c.FavoriteColor,
        })
        .Select(gcs => new ConsolidatedChild()
        {
            School = gcs.Key.School,
            Friend = gcs.Key.Friend,
            FavoriteColor = gcs.Key.FavoriteColor,
            Children = gcs.ToList(),
        });
Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 3
    Let's say I have lot's of properties in the group by, is there a cleaner way of doing this then listing all the properties? – guiomie Aug 21 '15 at 18:35
  • 4
    @guiomie - I wouldn't say that there was a cleaner way. You could serialize the object into a single string and group on that, but that would require more code elsewhere. So, in my mind, this answer is the cleanest way regardless how many properties. – Enigmativity Aug 21 '15 at 23:03
  • 3
    @Doppelganger - I rolled back your edit for two reasons. The choice of using the final comma (after `FavoriteColor`) is on purpose - it is legal syntax and it enables easier refactoring of code. The choice of using `gcs` rather than `gc` for the grouping variable is also on purpose - it shows me that it is a "group of many c's". – Enigmativity Nov 28 '15 at 01:05
  • 1
    I thought for sure that wouldn't compile, but you're absolutely right. As for renaming your variable, that was just to get past the six character limit. I never like to mess with someone's variable names. Anyway, thanks again for the awesome answer! – Doppelganger Nov 30 '15 at 20:16
  • 1
    Can you make an alternate example for method syntax? – Alexander Ryan Baggett Feb 12 '19 at 22:12
  • 1
    @AlexanderRyanBaggett - Done. – Enigmativity Feb 12 '19 at 22:17
262

Given a list:

var list = new List<Child>()
{
    new Child()
        {School = "School1", FavoriteColor = "blue", Friend = "Bob", Name = "John"},
    new Child()
        {School = "School2", FavoriteColor = "blue", Friend = "Bob", Name = "Pete"},
    new Child()
        {School = "School1", FavoriteColor = "blue", Friend = "Bob", Name = "Fred"},
    new Child()
        {School = "School2", FavoriteColor = "blue", Friend = "Fred", Name = "Bob"},
};

The query would look like:

var newList = list
    .GroupBy(x => new {x.School, x.Friend, x.FavoriteColor})
    .Select(y => new ConsolidatedChild()
        {
            FavoriteColor = y.Key.FavoriteColor,
            Friend = y.Key.Friend,
            School = y.Key.School,
            Children = y.ToList()
        }
    );

Test code:

foreach(var item in newList)
{
    Console.WriteLine("School: {0} FavouriteColor: {1} Friend: {2}", item.School,item.FavoriteColor,item.Friend);
    foreach(var child in item.Children)
    {
        Console.WriteLine("\t Name: {0}", child.Name);
    }
}

Result:

School: School1 FavouriteColor: blue Friend: Bob
    Name: John
    Name: Fred
School: School2 FavouriteColor: blue Friend: Bob
    Name: Pete
School: School2 FavouriteColor: blue Friend: Fred
    Name: Bob
CarenRose
  • 1,266
  • 1
  • 12
  • 24
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • 4
    For those of us who prefer the fluent interface. One tiny quibble: using the same variable "x" in both Func definitions isn't very clear for newer users. I'd recommend changing to match the one above, where "c" is the child, and "gcs" is the grouped children. – Michael Blackburn Nov 19 '12 at 15:46
  • 4
    @jazmatician _ I agree with you on the point that re-using `x` might confuse some, but not on the choice for variable names. I'll change it to `x` and `y` to diferentiate. – Jamiec Nov 19 '12 at 15:51
  • The variable names aren't my choice, either. In fact, when writing that I struggled to figure out what "gcs" meant to the author. Best I could come up with was "group (of) Cs." Anyway, I only recommended it to try to make it easy for someone to make the mental map between the two syntaxes. (syntaces? I bet syntax is one of those words which is its own plural. Because this is English, why would "syntax" be subject to syntactic rules about plurals?) – Michael Blackburn Nov 19 '12 at 16:51
  • 1
    to answer my own tangent: https://en.wiktionary.org/wiki/syntax – Michael Blackburn Nov 19 '12 at 16:51
  • 2
    I disagree with this opinion Michael. In my opinion, x should be used in both places. The only time it should not is when you use a Func withing another Hunc, then you should go to y. Otherwise it becomes confusing. – Serj Sagan Oct 30 '14 at 16:17