Linq order by、group by 和 order by 每组?

问题描述 投票:0回答:5

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

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

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

所以结果应该是这样的:

John 100
John 80
Lucy 80
Lucy 50
Lucy 40
Eric 70
Eric 30

我创建了以下查询:

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

但这会返回

IEnumerable
IGrouping
,并且我无法对内部列表进行排序,除非我在另一个
foreach
查询中执行此操作并使用
AddRange
将结果添加到不同的列表。

有更漂亮的方法吗?

c# linq group-by sql-order-by
5个回答
165
投票

当然:

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

22
投票

无需投影的方法:

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

18
投票

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

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

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

.SelectMany(group => group)

您始终可以将两者折叠成一个 单个

SelectMany
调用,一起进行投影和展平。


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

First
查询。
    


6
投票

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



2
投票

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)) { ------------------------ -------------------------- } }

	
© www.soinside.com 2019 - 2024. All rights reserved.