【问题标题】:Linq order by, group by and order by each group?Linq order by,group by 和 order by 每组?
【发布时间】:2011-06-28 04:12:09
【问题描述】:

我有一个看起来像这样的对象:

public class Student
{
    public string Name { get; set; } 
    public int Grade { get; set; }
}

我想创建以下查询:按学生姓名对成绩进行分组,按成绩对每个学生组进行排序,并按每个组中的最高成绩对组进行排序。

所以它看起来像这样:

A 100
A 80
B 80
B 50
B 40
C 70
C 30

我创建了以下查询:

StudentsGrades.GroupBy(student => student.Name)
    .OrderBy(studentGradesGroup => studentGradesGroup.Max(student => student.Grade));

但这会返回IEnumerableIGrouping,我无法对里面的列表进行排序,除非我在另一个foreach 查询中这样做并使用AddRange 将结果添加到不同的列表中。

有没有更漂亮的方法来做到这一点?

【问题讨论】:

    标签: c# linq group-by sql-order-by


    【解决方案1】:

    或者,您可以这样做:

         var _items = from a in StudentsGrades
                      group a by a.Name;
    
         foreach (var _itemGroup in _items)
         {
            foreach (var _item in _itemGroup.OrderBy(a=>a.grade))
            {
               ------------------------
               --------------------------
            }
         }
    

    【讨论】:

      【解决方案2】:

      不用投影的方法:

      StudentsGrades.OrderBy(student => student.Name).
      ThenBy(student => student.Grade);
      

      【讨论】:

      • 我认为这是因为虽然它会按要求对数据进行排序,但这是偶然的。表现最好的学生的顺序也是按字母顺序排列的。如果你给学生 C 90 分,他们应该出现在学生 B 之上。在这个答案中他们不会。
      【解决方案3】:

      试试这个...

      public class Student 
          {
              public int Grade { get; set; }
              public string Name { get; set; }
              public override string ToString()
              {
                  return string.Format("Name{0} : Grade{1}", Name, Grade);
              }
          }
      
      class Program
      {
          static void Main(string[] args)
          {
      
            List<Student> listStudents = new List<Student>();
            listStudents.Add(new Student() { Grade = 10, Name = "Pedro" });
            listStudents.Add(new Student() { Grade = 10, Name = "Luana" });
            listStudents.Add(new Student() { Grade = 10, Name = "Maria" });
            listStudents.Add(new Student() { Grade = 11, Name = "Mario" });
            listStudents.Add(new Student() { Grade = 15, Name = "Mario" });
            listStudents.Add(new Student() { Grade = 10, Name = "Bruno" });
            listStudents.Add(new Student() { Grade = 10, Name = "Luana" });
            listStudents.Add(new Student() { Grade = 11, Name = "Luana" });
            listStudents.Add(new Student() { Grade = 22, Name = "Maria" });
            listStudents.Add(new Student() { Grade = 55, Name = "Bruno" });
            listStudents.Add(new Student() { Grade = 77, Name = "Maria" });
            listStudents.Add(new Student() { Grade = 66, Name = "Maria" });
            listStudents.Add(new Student() { Grade = 88, Name = "Bruno" });
            listStudents.Add(new Student() { Grade = 42, Name = "Pedro" });
            listStudents.Add(new Student() { Grade = 33, Name = "Bruno" });
            listStudents.Add(new Student() { Grade = 33, Name = "Luciana" });
            listStudents.Add(new Student() { Grade = 17, Name = "Maria" });
            listStudents.Add(new Student() { Grade = 25, Name = "Luana" });
            listStudents.Add(new Student() { Grade = 25, Name = "Pedro" });
      
            listStudents.GroupBy(g => g.Name).OrderBy(g => g.Key).SelectMany(g => g.OrderByDescending(x => x.Grade)).ToList().ForEach(x => Console.WriteLine(x.ToString()));
          }
      }
      

      【讨论】:

        【解决方案4】:

        当然:

        var query = grades.GroupBy(student => student.Name)
                          .Select(group => 
                                new { Name = group.Key,
                                      Students = group.OrderByDescending(x => x.Grade) })
                          .OrderBy(group => group.Students.First().Grade);
        

        请注意,您可以在订购后只获得每个组中的第一名,因为您已经知道第一个条目将获得最高分。

        然后你可以显示它们:

        foreach (var group in query)
        {
            Console.WriteLine("Group: {0}", group.Name);
            foreach (var student in group.Students)
            {
                Console.WriteLine("  {0}", student.Grade);
            }
        }
        

        【讨论】:

        • 该 var 组变量上没有 Key 属性。
        • 谢谢!这是完成的查询 - studentGrades.GroupBy(student => student.Name) .Select(group => new { Students = group.OrderByDescending(x => x.Grade) }) .OrderByDescending(group => group.Students。 First().Grade) .SelectMany(group => group.Students)
        【解决方案5】:

        我认为您需要一个额外的投影,将每个组映射到组的排序版本:

        .Select(group => group.OrderByDescending(student => student.Grade))
        

        您似乎也可能想要在此之后进行另一个展平操作,这将为您提供一系列学生而不是一系列组:

        .SelectMany(group => group)
        

        您始终可以将两者折叠成一个单个 SelectMany 调用,将投影和展平一起进行。


        编辑: 正如 Jon Skeet 指出的那样,整体查询存在一定的低效率;从对每个组进行排序获得的信息不会用于对组本身进行排序。通过将每个组的排序移动到组本身的排序之前Max 查询可以躲避为更简单的First 查询。

        【讨论】:

          猜你喜欢
          • 2017-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-16
          • 2021-02-22
          • 1970-01-01
          • 1970-01-01
          • 2011-04-18
          相关资源
          最近更新 更多