3 nested groups with linq
I'm trying to get the 4th list of list of lists List<List<List<List<int>>>>
. From my Xml that 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 output structure 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 node attributes first by number of pages, then by zip, then by carrier. Then I will need to iterate over the list of results and process each request in a specific order. I am having problems getting the syntax for 3 nested groups. I have made sure that two nested groups can help me get the third.
here is my code.
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;
source to share
If nothing else I believe this code answers your question. Having to handle four nested lists is pretty tricky, and if you can refactor your solution to something simpler, you will likely find your code 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();
source to share
I'm not sure how to do this with XML, but if you have already transferred the claim to an array of some type Claim
(for example, in the code claims
has a type Claim[]
) and type Claim
a property or field called Key
, Carrier
, Zip
and Pages
then it 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 this page, mail and media, for example:
var myclaim = dic[4][34343]["carB"];
I decided to give you a way to translate to Dictionary<TKey, TValue>
instead List<T>
because translation to List
loses the key, so the only way to get the key (page, zip or carrier) would be to traverse the list down, which can get ugly and complicated. Sorry if the dictionary won't work for you.
source to share