Does Linq organize, group, and arrange for each group?

I have an object that looks something like this:

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

I would like to create the following query: group grades by student name, sort each group of students by grade, and group orders by maximum grade in each group.

So it will look like this:

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

I created the following query:

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

But this returns IEnumerable IGrouping , and I cannot sort the list inside, unless I do this in another foreach query and add the results to another list using AddRange .

Is there a nicer way to do this?

+48
c # linq sql-order-by group-by
Feb 16 2018-11-11T00:
source share
5 answers

Sure:

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

Please note that you can leave the first class in each group after ordering, because you already know that the first record will be at the highest level.

Then you can display them with:

 foreach (var group in query) { Console.WriteLine("Group: {0}", group.Name); foreach (var student in group.Students) { Console.WriteLine(" {0}", student.Grade); } } 
+99
Feb 16 '11 at 7:40
source share
— -

I think you need an additional projection that maps each group to a sorted version of the group:

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



It also looks like after that you will need another smoothing operation that will give you a sequence of students instead of a sequence of groups:

 .SelectMany(group => group) 

You can always collapse both into a single SelectMany call that performs projection and flattening.




EDIT: As John Skeet points out, there is some inefficiency in the overall query; information obtained by sorting each group is not used in ordering the groups themselves. By moving the sorting of each group to ordering the groups themselves, the Max query can be diverted to a simpler First query.

+10
Feb 16 2018-11-11T00:
source share

A way to do this without projecting:

 StudentsGrades.OrderBy(student => student.Name). ThenBy(student => student.Grade); 
+7
Jul 08 '13 at 14:51
source share

try it...

 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())); } } 
+3
Nov 25 '11 at 20:22
source share

Alternatively, you can do the following:

  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)) { ------------------------ -------------------------- } } 
+1
May 21 '15 at 19:31
source share



All Articles