4

I am trying to get 4 List deep List collection, List<List<List<List<int>>>>. From my Xml which looks like

<root> 
    <Claim key="1" carrier="carA" zip="34343" pages="1"/>
    <Claim key="2" carrier="carA" zip="34343" pages="2"/>
    <Claim key="3" carrier="carB" zip="10505" pages="2"/>
    <Claim key="4" carrier="carB" zip="10505" pages="4"/> 
    <Claim key="5" carrier="carB" zip="10505" pages="4"/>
</root>

the structure of the output should look like

-all
   -1
       -34343
           -carA
                   -1

   -2
       -34343
           -carA
                   -2

       -10505
               -carB
                   -3
   -4
       -10505
           -carB
                    -4
                    -5

the goal is to sort my XML based on the node attributes first by number of pages, then by zip, then by carrier. I will then need to cycle through the result list and process each claim in the particular order. I am having trouble getting the syntax right for 3 nested groups. I have accomplished getting 2 nested groups can anyone help me get the third.

here is my code so far.

var query = from claim in root.Elements("Claim")
                        group claim by claim.Attributes("Pages").First().Value into pageGroups
                        from zipGroups in
                            (from claim in pageGroups
                             group claim by int.Parse(claim.Attributes("CarrierZip").First().Value))
                        group zipGroups by pageGroups.Key;
kds6253
  • 835
  • 1
  • 12
  • 17
  • 2
    The output you've given seems to be for a different input than the one you posted. It might be easier to answer if the relationship was more obvious. – Paul Phillips Mar 20 '12 at 19:25
  • Where is Car C and car D in the example? – ΩmegaMan Mar 20 '12 at 19:28
  • Sorry, i just put random data together, i have fixed it. it should all go together now – kds6253 Mar 20 '12 at 19:30
  • 2
    Come on, give a guy a break - it is completely clear what is the question: "first by number of pages, then by zip, then by carrier" – Kobi Mar 20 '12 at 19:30
  • 1
    What has changed since http://stackoverflow.com/questions/9777885/sort-and-group-xml-based-on-attributes ? – L.B Mar 20 '12 at 19:33
  • I need to get the claims put into groups verses just being sorted in one set of groups. – kds6253 Mar 20 '12 at 19:36
  • in my previous question i have the output as a List>. I am able to get List>> but i need List>>> – kds6253 Mar 20 '12 at 19:38
  • @kds6253 have you read Jon Skeet's last comment? – L.B Mar 20 '12 at 19:39
  • yes and I have gotten to the point where i can get 2 nested groups working but i am having trouble getting the third nested group to work. – kds6253 Mar 20 '12 at 19:40
  • Sorry I didn't realize my code didn't get attached, it is now. – kds6253 Mar 20 '12 at 19:45

2 Answers2

5

I'm not sure how to do this with XML, but if you've already translated the claims into an array of some type Claim (e.g., in the code, claims is of type Claim[]) and the Claim type has properties or fields called Key, Carrier, Zip, and Pages then this should work.

var dic = (from claim in claims
           group claim by claim.Pages into pageGroup
           select new {
               Page = pageGroup.Key,
               Entries =
                   (from zentry in pageGroup
                    group zentry by zentry.Zip into zipGroup
                    select new {
                        Zip = zipGroup.Key,
                        Entries =
                            (from centry in zipGroup
                             group centry by centry.Carrier into carrierGroup
                             select new { Carrier = carrierGroup.Key, Entries = carrierGroup.AsEnumerable() })
                            .ToDictionary(ent => ent.Carrier, ent => ent.Entries)
                    }).ToDictionary(ent => ent.Zip, ent => ent.Entries)
           }).ToDictionary(ent => ent.Page, ent => ent.Entries);

It's not very clean, but it works. You can select a claim with the given page, zip, and carrier like so:

var myclaim = dic[4][34343]["carB"];

I chose to give you a way to translate into Dictionary<TKey, TValue> instead of List<T> because translating to List loses the key, so the only way to get the key (the page, zip or carrier) would be to traverse the list down which could get ugly and complicated. Sorry if a Dictionary won't work for you.

leviathanbadger
  • 1,682
  • 15
  • 23
4

If nothing else I believe this code answers your question. Having to handle four nested lists is pretty complex and if you can refactor your solution into something simpler you will probably find that your code will be easier to maintain.

var xml = @"<root>  
  <Claim key=""1"" carrier=""carA"" zip=""34343"" pages=""1""/> 
  <Claim key=""2"" carrier=""carA"" zip=""34343"" pages=""2""/> 
  <Claim key=""3"" carrier=""carB"" zip=""10505"" pages=""2""/> 
  <Claim key=""4"" carrier=""carB"" zip=""10505"" pages=""4""/>  
  <Claim key=""5"" carrier=""carB"" zip=""10505"" pages=""4""/>
</root>";

var xElement = XElement.Parse(xml);

var claims = xElement
  .Elements("Claim")
  .Select(
    x => new {
      Key = (Int32) x.Attribute("key"),
      Carrier = (String) x.Attribute("carrier"),
      Zip = (Int32) x.Attribute("zip"),
      Pages = (Int32) x.Attribute("pages")
    }
  );

var lists = claims
  .OrderBy(claim => claim.Pages)
  .GroupBy(claim => claim.Pages)
  .Select(pagesGroup => pagesGroup
    .OrderBy(claim => claim.Zip)
    .GroupBy(claim => claim.Zip)
    .Select(zipGroup => zipGroup
      .OrderBy(claim => claim.Carrier)
      .GroupBy(claim => claim.Carrier)
      .Select(carrierGroup => carrierGroup
        .OrderBy(claim => claim.Key)
        .Select(claim => claim.Key)
        .ToList()
      )
      .ToList()
    )
    .ToList()
  )
  .ToList();
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • This way looks like it will work, but is there a reason you went this way apposed to just adding another group in the LINQ statement i had? – kds6253 Mar 20 '12 at 20:10
  • For me your question wasn't so easy to understand so I tried to write my own code to get a better understanding of what you wanted to do. Besides you added your code after I started working on my answer. – Martin Liversage Mar 20 '12 at 20:14
  • lets say I wanted to order the groups so that if a three carrierGroups contain 1 claim and 2 more carrier groups contain 2 claims that the carrier groups with 1 claim are listed before the carrier groups with 2 names. This would need to happen after the zips are ordered. So basically we don't need the carrier groups ordered by carrier name but by size of the groups. would that be possible with this setup? – kds6253 Mar 20 '12 at 21:50