Leo Messi
Leo Messi

Reputation: 6186

Nested GroupBy in C#

Having an object with this structure:

public class GroupedObject
{
    public int id { get; set; }
    public string name { get; set; }
    public int value { get; set; }
    public string color { get; set; }
}

Here it is grouped by one of its attributes, id.

var myObj = someResponse
    .Select(d => new GroupedObject
    {
        id = d.id,
        name = d.name,
        value = d.value,
        color = d.color
    })
    .GroupBy(o => o.id)
    .ToDictionary(a => a.Key, a => a.Select(o => o).ToList());

The structure is:

id - id, name, value, color
id - id, name, value, color
id - id, name, value, color

What I want to do is to group it again by name, to have a nested structure like this:

id - name - id, name, value, color
   - name - id, name, value, color
id - name - id, name, value, color
   - name - id, name, value, color 
   - name - id, name, value, color 
   - name - id, name, value, color 
id - name - id, name, value, color
   - name - id, name, value, color 
   - name - id, name, value, color 

Trying to use GroupBy twice didn't work. Neither by transforming it with ToList and grouping after that.

 var myObj = someResponse
        .Select(d => new GroupedObject
        {
            id = d.id,
            name = d.name,
            value = d.value,
            color = d.color
        })
        .GroupBy(o => o.id).GroupBy(o => o.name)
        .ToDictionary(a => a.Key, a => a.Select(o => o).ToList());

Upvotes: 1

Views: 915

Answers (2)

Darjan Bogdan
Darjan Bogdan

Reputation: 3900

You were on the right track, however here is the LINQ to achieve two nested levels of grouping:

someResponse
    .Select(d => new GroupedObject
    { 
        id = d.id,
        name = d.name,
        value = d.value,
        color = d.color
    })
    .GroupBy(o => o.id)
    .ToDictionary(
        a => a.Key,
        a => a.GroupBy(o => o.name).ToDictionary(o => o.Key, o => o));

This will result in object of type: Dictionary<int, Dictionary<string, IGrouping<string, GroupedObject>>>

Taken that into account, last IGrouping<string, GroupedObject> type can be changed/projected into different type specifying suitable lamda inside nested ToDictionary call:

e.g. Changing call into ToDictionary(o => o.Key, o => o.ToList()) results with Dictionary<int, Dictionary<string, List<GroupedObject>>>

Upvotes: 2

Cetin Basoz
Cetin Basoz

Reputation: 23817

Using comprehension syntax might be easier:

var myObj = from sr in someResponse
    .Select(d => new GroupedObject
    {
        id = d.id,
        name = d.name,
        value = d.value,
        color = d.color
    })
    group sr by sr.id into g1
    select new {
       ID = g1.Key,
       NamesGroup = from n in g1
                    group n by n.name into g2
                    select new {
                      Name = g2.Key,
                      ...
                    }
    };

Note: If you download then wonderful LINQPad from LINQPad.net, in Samples you would find a very nice nested grouping sample using Northwind sample database.

Upvotes: 0

Related Questions