In this contrived example, which closely resembles my real-world problem, I have a data set coming from an external source. Each record from the external source takes the following form:
[Classification] NVARCHAR(32),
[Rank]           INT,
[Data]           NVARCHAR(1024)
I am looking to build an object where the Rank and Data are patched into a single instance of a response object that contains list properties for the three hard-coded Classification values, ordered by Rank.
I have something that works, but I can't help but think that it could be done better. This is what I have:
public static void Main()
{
    IEnumerable<GroupingTestRecord> records = new List<GroupingTestRecord>
    {
        new GroupingTestRecord { Classification = "A", Rank = 1, Data = "A1" },
        new GroupingTestRecord { Classification = "A", Rank = 2, Data = "A2" },
        new GroupingTestRecord { Classification = "A", Rank = 3, Data = "A3" },
        new GroupingTestRecord { Classification = "B", Rank = 1, Data = "B1" },
        new GroupingTestRecord { Classification = "B", Rank = 2, Data = "B2" },
        new GroupingTestRecord { Classification = "B", Rank = 3, Data = "B3" },
        new GroupingTestRecord { Classification = "C", Rank = 1, Data = "C1" },
        new GroupingTestRecord { Classification = "C", Rank = 2, Data = "C2" },
        new GroupingTestRecord { Classification = "C", Rank = 3, Data = "C3" },
    };
    GroupTestResult r = new GroupTestResult
    {
        A = records.Where(i => i.Classification == "A").Select(j => new GroupTestResultItem { Rank = j.Rank, Data = j.Data, }).OrderBy(k => k.Rank),
        B = records.Where(i => i.Classification == "B").Select(j => new GroupTestResultItem { Rank = j.Rank, Data = j.Data, }).OrderBy(k => k.Rank),
        C = records.Where(i => i.Classification == "C").Select(j => new GroupTestResultItem { Rank = j.Rank, Data = j.Data, }).OrderBy(k => k.Rank),
    };
The source record DTO:
public class GroupingTestRecord
{
    public string Classification { get; set; }
    public int? Rank { get; set; }
    public string Data { get; set; }
}
The destination single class:
public class GroupTestResult
{
    public IEnumerable<GroupTestResultItem> A { get; set; }
    public IEnumerable<GroupTestResultItem> B { get; set; }
    public IEnumerable<GroupTestResultItem> C { get; set; }
}
The distination child class:
public class GroupTestResultItem
{
    public int? Rank { get; set; }
    public string Data { get; set; }
}
Ouput
{
   "A":[
      {
         "Rank":1,
         "Data":"A1"
      },
      {
         "Rank":2,
         "Data":"A2"
      },
      {
         "Rank":3,
         "Data":"A3"
      }
   ],
   "B":[
      {
         "Rank":1,
         "Data":"B1"
      },
      {
         "Rank":2,
         "Data":"B2"
      },
      {
         "Rank":3,
         "Data":"B3"
      }
   ],
   "C":[
      {
         "Rank":1,
         "Data":"C1"
      },
      {
         "Rank":2,
         "Data":"C2"
      },
      {
         "Rank":3,
         "Data":"C3"
      }
   ]
}
Fiddle
Is there a better way to achieve my goal here?
The same JSON output was achieved using GroupBy first on the Classification and applying ToDictionary on the resulting IGrouping<string, GroupingTestRecord>.Key
var r = records
    .GroupBy(_ => _.Classification)
    .ToDictionary(
        k => k.Key, 
        v => v.Select(j => new GroupTestResultItem { Rank = j.Rank, Data = j.Data, }).OrderBy(k => k.Rank).ToArray()
    );
var json = JsonConvert.SerializeObject(r);
Console.WriteLine(json);
which should easily deserialize to the destination single class (for example on a client)
var result = JsonConvert.DeserializeObject<GroupTestResult>(json);
is it possible to get the top level result into a
GroupTestResultobject?
Build the result from the dictionary
var result = new GroupTestResult {
    A = r.ContainsKey("A") ? r["A"] : Enumerable.Empty<GroupTestResultItem>();,
    B = r.ContainsKey("B") ? r["B"] : Enumerable.Empty<GroupTestResultItem>();,
    C = r.ContainsKey("C") ? r["C"] : Enumerable.Empty<GroupTestResultItem>();,
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With