0

I want to create new list of list on basis of a single list. I have a list like

public class OfficeLocator
{
    public String id{ get; set; }
    public string Geography{ get; set; }
    public string Country{ get; set; }
    public string State{ get; set; }
    public string OfficeName{ get; set; }
}

I am trying to prepare an tree structured list

GeographyName="Asia",
{ 
   Country = "China",
   {
      State = "Hunan",
        {
            {
                OfficeId = "1",
                OfficeName = "Office 1"
            },
            {
                OfficeId = "2",
                OfficeName = "Office 2"
            }
        },
      State = "Hubei"
        {
            {
                OfficeId = "3",
                OfficeName = "Office 3"
            }
        }
    },
    Country = "India",
    {
      State = "Maharashtra",
        {
            {
                OfficeId = "4",
                OfficeName = "Office 4"
            },
            {
                OfficeId = "5",
                OfficeName = "Office 5"
            }
        },
      State = "Punjab"
        {
            {
                OfficeId = "6",
                OfficeName = "Office 6"
            }
        }
    },
},
GeographyName="Europe",
{ 
   Country = "UK",
   {
      State = "York",
        {
            {
                OfficeId = "7",
                OfficeName = "Office 7"
            },
            {
                OfficeId = "8",
                OfficeName = "Office 8"
            }
        }     
    }
}

I tried using some group by on Geography and Country. But I am not getting the required output.
I can use looping logic to get the result, but I want to avoid it and try something with linq.

Drag and Drop
  • 2,672
  • 3
  • 25
  • 37

3 Answers3

4

Something like this?

var allRegionGroups = allOfficeLocators
    .GroupBy(ol => ol.Geography)
    .Select(gGroup => new
    {
        GeographyName = gGroup.Key,
        Countries = gGroup
            .GroupBy(ol => ol.Country)
            .Select(cGroup => new
            {
                Country = cGroup.Key,
                States = cGroup
                  .GroupBy(ol => ol.State)
                  .Select(sGroup => new
                  {
                      State = sGroup.Key,
                      OfficeList = sGroup
                       .Select(ol => new { OfficeId = ol.id, ol.OfficeName })
                       .ToList()
                  })
                 .ToList()
            })
            .ToList()
    })
    .ToList();

How you can access all properties of the anonymous types:

foreach (var region in allRegionGroups)
{
    string geographyName = region.GeographyName;
    var allCountries = region.Countries;
    foreach (var c in allCountries)
    {
        string country = c.Country;
        var allStates = c.States;
        //  and so on...
    }
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Thanks for the solution, But Is there any way to have the collection as a List so I can filter data directly from it instead of going for foreach loop – Girish Mahida Dec 05 '17 at 18:27
  • It is a list and you can query it directly – Tim Schmelter Dec 05 '17 at 18:28
  • When I am trying to convert it to any type I am getting type cast error for Anonymys type to List. For ex: If I try to create a tree structure of it with having recurrence logic like Class Node { string id; string name; List Nodes} – Girish Mahida Dec 05 '17 at 18:57
  • You haven't showed your class so i couldn't create instances of it. You have to use new ClassNane where i have used new{} to create anonymous types. – Tim Schmelter Dec 05 '17 at 19:00
  • Yes I did that instead of new I have my class name but for last node it gives an exception for converting List can not be converted from anonymys – Girish Mahida Dec 05 '17 at 19:03
  • I can't fix code that i dont see. However, i cant look at it now anyway maybe tomorrow. I hop you can fix it yourself until then. Otherwise you might want to ask another question and show your existing class there – Tim Schmelter Dec 05 '17 at 19:05
  • Thanks for your help. I am able to resolve the issue. – Girish Mahida Dec 06 '17 at 05:46
  • Hi, I tried to follow similar approach to one of my [question](https://stackoverflow.com/questions/47676098/group-by-inner-list-parameter-to-filter-outer-list-data). But not getting any success. Can you help me in it. – Girish Mahida Dec 06 '17 at 16:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/160632/discussion-between-tim-schmelter-and-girish-mahida). – Tim Schmelter Dec 06 '17 at 16:34
  • I have joined the chat session with you – Girish Mahida Dec 06 '17 at 17:22
0

GroupBy, has some overload that comes handy in those case:

var query = locations.GroupBy(
            x => x.Geography,
            (a, aGroup) => new
            {
                A = a,
                Items = aGroup.GroupBy(
                    x => x.Country,
                    (b, bGroup) => new
                    {
                        B = b,
                        Items = bGroup.GroupBy(
                            x => x.State,
                            (c, cGroup) => new
                            {
                                B = c,
                                Items = cGroup.Select(i => new {i.Id, i.OfficeName})
                            })
                    })
            });

It's a little bit clearer to read and write.
The Anonimised object can be replace by your own class if needed.

Drag and Drop
  • 2,672
  • 3
  • 25
  • 37
0

you could achieve the same result as Tim mentioned but instead of using the method syntax, rely on the query syntax for debatable better readability

var projection = from location in locations
                 group location by location.Geography into geographies
                 select new
                 {
                    Geography = geographies.Key,
                    Countries = from geography in geographies
                                group geography by geography.Country into countries
                                select new
                                {
                                    Country = countries.Key,
                                    States = from country in countries
                                            group country by country.State into states
                                            select new
                                            {
                                                State = states.Key,
                                                Offices = from state in states
                                                        select new
                                                        {
                                                            Id = state.Id,
                                                            Office = state.Office,
                                                        }
                                             }
                                }
                };

and the end result would look like this

enter image description here

Dan Dohotaru
  • 2,809
  • 19
  • 15
  • Hi, I tried to follow similar approach to one of my [question](https://stackoverflow.com/questions/47676098/group-by-inner-list-parameter-to-filter-outer-list-data). But not getting any success. Can you help me in it. – Girish Mahida Dec 06 '17 at 16:26