61 votes

Linq classer par, grouper par et classer par groupe?

J'ai un objet qui ressemble à quelque chose comme ça -

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

Je voudrais créer la requête suivante - groupe de nuances par le nom de l'étudiant, de l'ordre de chaque groupe d'étudiants en nuances, et l'ordre des groupes de max la note de chaque groupe.

Donc, il ressemblera à ceci -

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

J'ai créé la requête suivante -

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

Mais qui renvoie IEnumerable IGrouping, et je n'ai aucun moyen de trier la liste à l'intérieur, à moins que je ne que dans un autre foreach requête et ajouter le résultat à une autre liste à l'aide de AddRange.

Est-il plus belle façon de le faire?

124voto

Jon Skeet Points 692016

Sûr:

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

Notez que vous pouvez vous contenter de prendre la première note au sein de chaque groupe après la commande, car vous savez déjà que la première entrée aura la note la plus élevée.

Ensuite, vous pouvez les afficher avec:

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

20voto

Sawyer Points 77

La façon de le faire sans projection:

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

15voto

Ani Points 59747

Je pense que vous voulez être de projection que les cartes de chaque groupe à une triés-version du groupe:

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

Il apparaît aussi comme vous pourriez voulez une autre aplatissement de l'opération, après que ce qui vous donnera une séquence d'étudiants au lieu d'une séquence de groupes:

.SelectMany(group => group)

Vous pouvez toujours effondrement à la fois dans un seul SelectMany appel que le fait de la projection et de l'aplatissement de l'ensemble.


EDIT: Comme Jon Skeet, il y a certaines insuffisances dans l'ensemble de la requête; les informations obtenues par le tri de chaque groupe n'est pas utilisé dans la commande de groupes eux-mêmes. En déplaçant le tri de chaque groupe à venir avant la commande des groupes eux-mêmes, l' Max de la requête peut être esquivé en un simple First de la requête.

4voto

Bruno Torres Points 29

essaye ça...

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X