J'ai un objet qui ressemble à quelque chose comme ça:
public class Student
{
public string Name { get; set; }
public int Grade { get; set; }
}
J'aimerais créer la requête suivante: regrouper les notes par nom d'étudiant, classer chaque groupe d'étudiants par notes et classer les groupes par note maximale dans chaque groupe.
Donc ça va ressembler à ça:
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 cela retourne IEnumerable
IGrouping
, et je n'ai aucun moyen de trier la liste à l'intérieur, à moins que je ne le fasse dans une autre requête foreach
et ajoute les résultats à une autre liste à l'aide de AddRange
.
Y a-t-il une façon plus jolie de faire cela?
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);
}
}
La façon de le faire sans projection:
StudentsGrades.OrderBy(student => student.Name).
ThenBy(student => student.Grade);
Je pense que vous voulez une projection supplémentaire qui mappe chaque groupe à une version triée du groupe:
.Select(group => group.OrderByDescending(student => student.Grade))
Il apparaît également comme vous peut-être voulez après l'opération une autre opération d'aplatissement qui vous donnera une séquence d'étudiants au lieu d'une séquence de groupes:
.SelectMany(group => group)
Vous pouvez toujours réduire les deux en un appel niqueSelectMany
qui effectue la projection et l'aplatissement ensemble.
EDIT: Comme le souligne Jon Skeet, il y a certaines inefficacités dans la requête globale; les informations obtenues en triant chaque groupe ne sont pas utilisées dans l'ordre des groupes eux-mêmes. En déplaçant le tri de chaque groupe à venir avant l'ordre des groupes eux-mêmes, la requête Max
peut être modifiée dans une requête plus simple First
.
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()));
}
}
Sinon, vous pouvez faire comme ça:
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))
{
------------------------
--------------------------
}
}