我可以使用LINQ GroupBy更干净地进行此操作吗?

时间:2018-10-16 01:15:53

标签: c# .net linq

在这个与我的现实世界问题非常相似的人为例子中,我有一个来自外部来源的数据集。外部来源的每条记录都采用以下格式:

[Classification] NVARCHAR(32),
[Rank]           INT,
[Data]           NVARCHAR(1024)

我正在寻找一个对象,其中将RankData修补到响应对象的单个实例中,该实例包含三个硬编码的Classification值的列表属性,由Rank订购。

我有一些可行的方法,但我不禁认为可以做得更好。这就是我所拥有的:

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),
    };

源记录DTO:

public class GroupingTestRecord
{
    public string Classification { get; set; }
    public int? Rank { get; set; }
    public string Data { get; set; }
}

目标单班:

public class GroupTestResult
{
    public IEnumerable<GroupTestResultItem> A { get; set; }
    public IEnumerable<GroupTestResultItem> B { get; set; }
    public IEnumerable<GroupTestResultItem> C { get; set; }
}

占卜子班:

public class GroupTestResultItem
{
    public int? Rank { get; set; }
    public string Data { get; set; }
}

输出

{
   "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

在这里有更好的方法实现我的目标吗?

2 个答案:

答案 0 :(得分:4)

首先在GroupBy上使用Classification,然后在结果ToDictionary上应用IGrouping<string, GroupingTestRecord>.Key,即可获得相同的JSON输出

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);

应该很容易反序列化到目标单个类(例如在客户端上)

var result = JsonConvert.DeserializeObject<GroupTestResult>(json);
  

是否可以将顶级结果放入GroupTestResult对象中?

从字典构建结果

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>();,
};

答案 1 :(得分:3)

或者这个

var result = records.GroupBy(x => x.Classification)
                    .ToDictionary(x => x.Key, x => x.Select(y => new {y.Rank, y.Data})
                                                    .OrderBy(y => y.Rank));

Console.WriteLine(JsonConvert.SerializeObject(result));

Full Demo Here