Linq order by, group by e order by ciascun gruppo?

Ho un oggetto che sembra qualcosa di simile a questo:

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

Vorrei creare la seguente query: gruppo di gradi il nome dello studente, per ogni gruppo di studenti per gradi, e l’ordine dei gruppi in grado di max in ogni gruppo.

In modo che sarà simile a questa:

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

Ho creato la query seguente:

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

Ma che restituisce IEnumerable IGrouping, e non ho alcun modo per ordinare l’elenco all’interno, a meno che non lo faccio in un altro foreach query e aggiungere i risultati in un elenco diverso utilizzando AddRange.

C’è una bella maniera per fare che?

InformationsquelleAutor Rita | 2011-02-16

 

5 Replies
  1. 122

    Sicuro:

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

    Nota che si può ottenere via con solo il primo grado all’interno di ogni gruppo, dopo l’ordinazione, perché si conosce già la prima voce sarà avere il massimo dei voti.

    Quindi, è possibile visualizzare il loro:

    foreach (var group in query)
    {
        Console.WriteLine("Group: {0}", group.Name);
        foreach (var student in group.Students)
        {
            Console.WriteLine("  {0}", student.Grade);
        }
    }
    • Non c’è nessun Tasto di proprietà del gruppo var variabile.
    • Grazie! Questo è il termine query – studentGrades.GroupBy(studente => studente.Nome) .Selezionare(gruppo => nuovo { Studenti = gruppo.OrderByDescending(x => x.Grado) }) .OrderByDescending(gruppo =>.Studenti.Il primo().Grado) .SelectMany(gruppo =>.Studenti)
  2. 19

    Il modo per farlo senza di proiezione:

    StudentsGrades.OrderBy(student => student.Name).
    ThenBy(student => student.Grade);
    • Sono curioso di sapere perché questo sembra non essere la soluzione preferita…
    • Credo di si, perché mentre sarebbe in ordine i dati come richiesto, è per caso. L’ordine dei migliori studenti anche in ordine alfabetico. Se si danno allo Studente C a voto di 90, che dovrebbe apparire sopra Studente B. In questa risposta, che non.
  3. 15

    Penso si desidera un ulteriore proiezione che associa a ciascun gruppo, per l’ordinamento di una versione del gruppo:

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

    Appare anche come si potrebbe vuole un’altra operazione di appiattimento dopo di che, che vi darà una sequenza di studenti, invece di una sequenza di gruppi:

    .SelectMany(group => group)

    È sempre possibile crollo sia in un singolo SelectMany chiamata che fa la proiezione e l’appiattimento insieme.


    MODIFICA:
    Come Jon Skeet punti, ci sono alcune inefficienze nella query in generale; le informazioni acquisite dall’ordinamento di ciascun gruppo non viene utilizzato nell’ordinamento dei gruppi stessi. Spostando l’ordinamento di ciascun gruppo di prima l’ordine dei gruppi stessi, la Max query può essere schivato in un più semplice First query.

  4. 4

    provare questo…

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

    In alternativa si può fare come questo :

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

Lascia un commento