webentwicklung-frage-antwort-db.com.de

Linq Sortieren nach, Gruppieren nach und Ordnen nach jeder Gruppe?

Ich habe ein Objekt, das ungefähr so ​​aussieht:

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

Ich möchte die folgende Abfrage erstellen: Gruppennoten nach Schülernamen, Reihenfolge der Schülergruppen nach Noten und Reihenfolge der Gruppen nach Höchstnote in jeder Gruppe.

Also wird es so aussehen:

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

Ich habe die folgende Abfrage erstellt:

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

Aber das gibt IEnumerableIGrouping zurück und ich habe keine Möglichkeit, die Liste darin zu sortieren, es sei denn, ich mache das in einer anderen foreach - Abfrage und füge die Ergebnisse mit AddRange.

Gibt es einen schöneren Weg, das zu tun?

60
Rita

Sicher:

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

Beachten Sie, dass Sie nach der Bestellung in jeder Gruppe nur die erste Note erreichen können, da Sie bereits wissen, dass der erste Eintrag die höchste Note hat.

Dann könnten Sie sie anzeigen mit:

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

So geht das ohne Projektion:

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

Ich denke, Sie möchten eine zusätzliche Projektion, die jede Gruppe einer sortierten Version der Gruppe zuordnet:

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

Es sieht auch so aus, als ob Sie könnte danach eine weitere Glättungsoperation wünschen, die Ihnen eine Folge von Schülern anstelle einer Folge von Gruppen gibt:

.SelectMany(group => group)

Sie können jederzeit beide zu einem einzelnenSelectMany -Aufruf zusammenfassen, der die Projektion und das Reduzieren zusammen ausführt.


EDIT: Wie Jon Skeet betont, gibt es bestimmte Ineffizienzen in der Gesamtabfrage; Die Informationen, die beim Sortieren der einzelnen Gruppen gewonnen werden, werden nicht für die Reihenfolge der Gruppen selbst verwendet. Indem Sie die Sortierung der kommenden Gruppen verschieben vor die Reihenfolge der Gruppen selbst, kann die Abfrage Max in eine einfachere Abfrage First umgewandelt werden.

15
Ani

versuche dies...

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
Bruno Torres

Alternativ können Sie auch so vorgehen:

     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
agileDev