【问题标题】:How to get first record in each group using Linq如何使用 Linq 在每个组中获取第一条记录
【发布时间】:2013-09-25 18:55:58
【问题描述】:

考虑以下记录:

   Id          F1            F2             F3 
 -------------------------------------------------
   1           Nima          1990           10
   2           Nima          1990           11
   3           Nima          2000           12
   4           John          2001           1
   5           John          2002           2 
   6           Sara          2010           4

我想根据F1字段进行分组并按Id排序,并从与这些记录类似的组的第一条记录中获取所有字段:

   Id          F1            F2             F3 
 -------------------------------------------------
   1           Nima          1990           10
   4           John          2001           1
   6           Sara          2010           4

如何使用 linq 做到这一点?

【问题讨论】:

    标签: c# linq c#-4.0 linq-to-entities


    【解决方案1】:
    var result = input.GroupBy(x => x.F1, (key,g) => g.OrderBy(e => e.F2).First());
    

    【讨论】:

    • 这向我展示了使用 Fluent 语法的方式。 overloads for GroupBy 似乎给了你很大的力量 - 一个可以添加到长长的学习列表中!
    • @rogersillito 这就是为什么它被称为查询(Language Integrated Query - LINQ)的原因,GroupBy 也有很多重载但只有几个是常用的,这也取决于个人喜好,例如有些人喜欢写成.GroupBy(x=>x.F1).Select(g=>...),这样看起来更容易理解。
    • 你应该用.FirstOrDefault()替换.First(),否则你会得到异常:The method 'First' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead.
    • @NikolayKostov 我知道这一点,但我假设这里的 LINQ 用作 LINQ-to-object,而不是 LINQ-to-entities,所以我们可以安全地使用 .First()。 OP 的问题看起来真的很像关心 linq-to-object,尽管他也用linq-to-entities 标记了这个问题(不确定他是否理解那是什么)。
    • 我喜欢这个答案,很好。
    【解决方案2】:
    var res = from element in list
              group element by element.F1
                  into groups
                  select groups.OrderBy(p => p.F2).First();
    

    【讨论】:

    • 很高兴我找到了这个。我收到错误消息“方法 'First' 只能用作最终查询操作。请考虑在此实例中使用方法 'FirstOrDefault'。”从你的例子。查询后我对列表所做的唯一操作是将 myResult.ToList() 传递给方法。虽然使用 FirstOrDefault 解决了它
    • 会不会是OrderBy(p => p.Id),他们希望它按 ID 而非年份列排序。
    • 您能否为此提供一些帮助:stackoverflow.com/questions/44764687/…
    • 如果想从组中检索第一个和最后一个项目怎么办?
    【解决方案3】:

    @Alireza 的 awnser 是完全正确的,但是你在使用这段代码的时候一定要注意

    var res = from element in list
              group element by element.F1
                  into groups
                  select groups.OrderBy(p => p.F2).First();
    

    这与此代码类似,因为您对列表进行排序,然后进行分组,以便获得第一行组

    var res = (from element in list)
              .OrderBy(x => x.F2)
              .GroupBy(x => x.F1)
              .Select()
    

    现在,如果您想做一些更复杂的事情,比如采用相同的分组结果,但采用 F2 的第一个元素和 F3 的最后一个元素或更自定义的东西,您可以通过研究下面的代码来做到这一点

     var res = (from element in list)
              .GroupBy(x => x.F1)
              .Select(y => new
               {
                 F1 = y.FirstOrDefault().F1;
                 F2 = y.First().F2;
                 F3 = y.Last().F3;
               });
    

    所以你会得到类似的东西

       F1            F2             F3 
     -----------------------------------
       Nima          1990           12
       John          2001           2
       Sara          2010           4
    

    【讨论】:

    • 新对象的分隔符或分隔符应该是逗号而不是分号。请检查。
    • 不错的部分是 .First() 和 .Last()
    • 可能First() 部分在 EFCore 3.1 中不再受支持,您可能必须先实现数据。
    【解决方案4】:

    用它来实现你想要的。然后决定要返回哪些属性。

    yourList.OrderBy(l => l.Id).GroupBy(l => new { GroupName = l.F1}).Select(r => r.Key.GroupName)
    

    【讨论】:

      【解决方案5】:
      var res = (from element in list)
            .OrderBy(x => x.F2).AsEnumerable()
            .GroupBy(x => x.F1)
            .Select()
      

      在 OrderBy() 之后使用 .AsEnumerable()

      【讨论】:

        【解决方案6】:

        另一种方式:

        var result = input.GroupBy(i => i.F1).Select(g => g.First());
        

        您可以按多个字段分组:

        var result = input.GroupBy(i => new {i.F1, i.F2}).Select(g => g.First());
        

        如果您需要保持顺序,请使用查找:

        var result = input.ToLookup(i => i.F1).Select(g => g.First());
        

        【讨论】:

          【解决方案7】:

          这不是您要寻找的东西,但有时我们会寻找错误的东西,因为我们不知道存在什么。所以我的解决方案我觉得最直观:

          var dict = 
          input.OrderByDescending(x => x.Id)
               .GroupBy(x => x.F1)
               .ToDictionary(x => x.Key, x => new { x.First().F1, x.First().F2, x.First().F3});
          

          先订购,然后分组 - 直截了当。现在结果将是一个键类型对的列表❊。由于我们的表已经排序,我们可以选择第一个条目。此外,我建议将结果放入带有 ID 作为访问器的字典中,这是一种访问速度非常快且仍然灵活的数据结构。现在您可以使用

          dict[4].F1 // returns Nima
          

          ❊ 技术上它的 IEnumerable>

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-29
            • 1970-01-01
            • 2021-08-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多