C#Linq查询帮助删除foreach循环创建更清晰的代码

Dec*_*Key 4 c# linq

有没有办法使用linq删除for循环来解决我的问题

我想获得每个学生和该列表中每个主题的主题和总分:

IEnumerable<Student> students = new List<Student> {
    new Student() {Id = 1, Name = "John", Age = 13},
    new Student() {Id = 2, Name = "Mary", Age = 12},
    new Student() {Id = 3, Name = "Anne", Age = 14}
};
Run Code Online (Sandbox Code Playgroud)

我有第二个列表,其中包含所有分数和主题信息:

IEnumerable<StudentScore> studentScores = new List<StudentScore> {
    new StudentScore() {StudentId = 1, Subject = "Maths", Points = 54},
    new StudentScore() {StudentId = 1, Subject = "Maths", Points = 32},
    new StudentScore() {StudentId = 1, Subject = "English", Points = 55},
    new StudentScore() {StudentId = 1, Subject = "English", Points = 54},

    new StudentScore() {StudentId = 2, Subject = "Maths", Points = 44},
    new StudentScore() {StudentId = 2, Subject = "Maths", Points = 37},
    new StudentScore() {StudentId = 2, Subject = "English", Points = 59},
    new StudentScore() {StudentId = 2, Subject = "English", Points = 64},

    new StudentScore() {StudentId = 3, Subject = "Maths", Points = 53},
    new StudentScore() {StudentId = 3, Subject = "Maths", Points = 72},
    new StudentScore() {StudentId = 3, Subject = "English", Points = 54},
    new StudentScore() {StudentId = 3, Subject = "English", Points = 59},
};
Run Code Online (Sandbox Code Playgroud)

这是我提出的解决方案:

foreach (var student in students)
{
    foreach (var studentScore in studentScores.Select(ss=>ss.Subject).Distinct())
    {
        Console.WriteLine("Name: " + student.Name + " Subject:" + studentScore + "Score: " + studentScores.Where(ss => ss.StudentId == student.Id)
                                                                               .Where(ss => ss.Subject == studentScore)
                                                                               .Sum(ss => ss.Points));
    }
}
Run Code Online (Sandbox Code Playgroud)

das*_*ght 5

你的解决方案有腰带和吊带 - foreach循环与LINQ结合,其中LINQ部分取决于你进入foreach循环的值.

理解如何完全使用LINQ完成这一操作的技巧是实现LINQ处理表达式而不是语句.因此,您需要立即生成整个列表,然后在单个foreach循环中打印它,或者使用string.Format方法来完全避免循环.

以下是您准备数据的方式:

var rows = students
    .Join(
        studentScores
    ,   st => st.Id
    ,   sc => sc.StudentId
    ,   (st, sc) => new { Student = st, Score = sc }
    )
    .GroupBy(p => new { p.Student.Id, p.Score.Subject })
    .Select(g => new {
        Name = g.First().Student.Name
    ,   Subj = g.Key.Subject
    ,   Points = g.Sum(p => p.Score.Points)
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

现在,您可以在foreach循环中完成此操作,并打印准备好的结果:

foreach (var r in rows) {
    Console.WriteLine($"Name: {r.Name} Subject: {r.Subject} Score: {r.Score}");
}
Run Code Online (Sandbox Code Playgroud)