【问题标题】:LINQ with subselect and groupby to get only the latest version of each item in a list使用 subselect 和 groupby 的 LINQ 仅获取列表中每个项目的最新版本
【发布时间】:2009-01-13 00:06:29
【问题描述】:

我是 LINQ 的新手...

我有一个 IEnumerable 通用列表,其中包含不同版本的答案(每个版本都有问题的 FK)。从此列表中,我只需要获取最新版本答案的字典。

一个非常简化的类图:

问题
-ID
-问题
- ...其他属性

回答
-ID
-版本
-问题ID
-价值
- ...其他属性

目前我有以下内容:

IEnumerable<Answer> answers = GetAnswers();

IDictionary<long, AnswerDTO> latestVersionAnswers = new Dictionary<long, AnswerDTO>();
if (answers != null)
{
latestVersionAnswers = answers
      .OrderBy(e => e.ID)
      .GroupBy(e => e.Question.ID)
      .Select(g => new AnswerDTO
                        {
                             Version = g.Last().Version, // g.Select(e => e.Version).Max(), 
                             QuestionID = g.Key,
                             ID = g.Last().ID,
                             Value = g.Last().Value
                                 }).ToDictionary(c => c.QuestionID);
        }

虽然这在大多数情况下都有效,但您可以很快看到它需要一些认真的优化(并且有点脆弱,因为它取决于答案记录行顺序而不是“最大”逻辑)。使用 LINQ 执行此操作的最佳方法是什么,或者最好为每个循环执行多个?

  1. 如果我只需要版本(而不是 ID、值等),我就不需要 OrderBy,因为我可以只使用 g.Select(e => e.Version).Max()(或者我'现在已经看到C# List<> GroupBy 2 Values 的帖子,但这又只会返回密钥和一个属性:版本)。
  2. 最终,在这种特殊情况下,我更愿意只“过滤”原始列表并返回原始答案项,而不是涉及 AnswerDTO。

任何指点或帮助将不胜感激!

【问题讨论】:

    标签: c# linq lambda


    【解决方案1】:

    比如......

       private void button1_Click(object sender, EventArgs e)
        {
          List<Answer> list = GetAnswers();
    
          var dict = (from a in list
                     group a by a.QuestionID into grp
                     from g in grp
                     where g.Version == grp.Max(m => m.Version)
                     select new { id = g.QuestionID, q = g }).ToDictionary( o => o.id, o => o.q);
    
          StringBuilder sb = new StringBuilder();
          foreach (var elem in dict)
          {
            sb.AppendLine(elem.Key.ToString() + "-" + elem.Value.Version.ToString());
          }
          MessageBox.Show(sb.ToString());
        }
    
        private List<Answer> GetAnswers()
        {
          List<Answer> result = new List<Answer>();
          result.Add(new Answer() { ID = 1, QuestionID = 1, Version = 1 });
          result.Add(new Answer() { ID = 2, QuestionID = 1, Version = 2 });
          result.Add(new Answer() { ID = 3, QuestionID = 1, Version = 3 });
          result.Add(new Answer() { ID = 4, QuestionID = 2, Version = 1 });
          result.Add(new Answer() { ID = 5, QuestionID = 2, Version = 2 });
          result.Add(new Answer() { ID = 6, QuestionID = 2, Version = 3 });
          result.Add(new Answer() { ID = 7, QuestionID = 3, Version = 1 });
          result.Add(new Answer() { ID = 8, QuestionID = 3, Version = 2 });
          result.Add(new Answer() { ID = 9, QuestionID = 3, Version = 3 });
          result.Add(new Answer() { ID = 10, QuestionID = 3, Version = 4 });
          return result;
        }
    

    【讨论】:

    • 正是我想要的。所以你就是这样做的!感谢您的及时答复。
    【解决方案2】:
    latestVersionAnswers = answers
      .GroupBy(e => e.Question.ID)
      .Select(g => g.OrderByDescending(e => e.Version).First())
      .ToDictionary(e => e.Question.ID);
    

    或者,如果您更喜欢 ToDictionary 的选择重载:

    latestVersionAnswers = answers
      .GroupBy(e => e.Question.ID)
      .ToDictionary(
        g => g.Key,
        g => g.OrderByDescending(e => e.Version).First()
      );
    

    【讨论】:

      【解决方案3】:

      我只是重写数据模型以包含当前答案版本 ID。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-13
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 2018-07-03
        相关资源
        最近更新 更多