我有一个看起来像这样的对象:
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
将结果添加到不同的列表。
有更漂亮的方法吗?
当然:
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);
}
}
无需投影的方法:
StudentsGrades.OrderBy(student => student.Name).
ThenBy(student => student.Grade);
我认为你想要一个额外的投影,将每个组映射到该组的排序版本:
.Select(group => group.OrderByDescending(student => student.Grade))
看起来您可能想要在此之后进行另一次展平操作,这将为您提供一系列学生而不是一系列组:
.SelectMany(group => group)
您始终可以将两者折叠成一个 单个
SelectMany
调用,一起进行投影和展平。
编辑:
正如 Jon Skeet 指出的那样,整体查询存在一定的低效率;对每个组进行排序所获得的信息不会用于对组本身进行排序。通过将每个组的排序移至组本身的排序之前,可以将 Max
查询避开为更简单的
First
查询。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()));
}
}
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))
{
------------------------
--------------------------
}
}