次のようなオブジェクトがあります。
public class Student
{
public string Name { get; set; }
public int Grade { get; set; }
}
次のクエリを作成します:学生名で成績をグループ化し、各学生グループを成績で順序付けし、各グループの最大成績でグループを順序付けします。
したがって、次のようになります。
A 100
A 80
B 80
B 50
B 40
C 70
C 30
次のクエリを作成しました。
StudentsGrades.GroupBy(student => student.Name)
.OrderBy(studentGradesGroup => studentGradesGroup.Max(student => student.Grade));
しかし、それはIEnumerable
IGrouping
を返します。別のforeach
クエリでリストをソートし、AddRange
を使用して結果を別のリストに追加しない限り、リストをソートする方法はありません。
それを行うよりきれいな方法はありますか?
承知しました:
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);
注文後、各グループ内で最初の成績を取得するだけで済むことに注意してください。これは、最初のエントリが最高の成績を持つことが既にわかっているためです。
次に、それらを表示できます:
foreach (var group in query)
{
Console.WriteLine("Group: {0}", group.Name);
foreach (var student in group.Students)
{
Console.WriteLine(" {0}", student.Grade);
}
}
投影せずにそれを行う方法:
StudentsGrades.OrderBy(student => student.Name).
ThenBy(student => student.Grade);
各グループをグループのソートされたバージョンにマッピングする追加の投影が必要だと思います:
.Select(group => group.OrderByDescending(student => student.Grade))
また、あなたのように見えますmightその後に別の平坦化操作が必要です。これにより、グループのシーケンスではなく、学生のシーケンスが提供されます。
.SelectMany(group => group)
常に両方を折りたたみ、投影とフラット化を同時に行うsingleSelectMany
呼び出しにできます。
編集:ジョン・スキートが指摘するように、全体的なクエリには特定の非効率性があります。各グループのソートから得られる情報は、グループ自体の順序付けには使用されていません。各グループのソートを移動してbeforeグループ自体の順序付けを行うことで、Max
クエリをより単純なFirst
クエリに回避できます。
これを試して...
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()));
}
}
または、次のようにすることもできます。
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))
{
------------------------
--------------------------
}
}