簡體   English   中英

如何使用 Linq 在某些操作中聚合兩個 List?

[英]How can I aggregate two List in some operation by using Linq?

我已經定義了類 StudentData ,它包含 Name、Subject 屬性,它們是 Enum 類型,分數為 double。 一些數據填充在List結構StudentNameList和StudentDataList中。

public class StudentData
{
    public StudentName Name { get; set; }
    public Subject Subject { get; set; }
    public double Score { get; set; }

    public StudentData(StudentName name, Subject subject, double score)
    {
        Name = name;
        Subject = subject;
        Score = score;
    }
}

public enum StudentName
{
    Tom,
    Nikki,
    Benny
}

public enum Subject
{
    Math,
    Physic,
    History
}
    List<StudentName> studentName = new List<StudentName>();
    studentName.Add( StudentName.Benny);
    studentName.Add(StudentName.Nikki);
    studentName.Add(StudentName.Tom);

    List<StudentData> studentDataList = new List<StudentData>();

    studentDataList.Add(new StudentData(StudentName.Benny, Subject.History, 85));
    studentDataList.Add(new StudentData(StudentName.Benny, Subject.Math, 60));
    studentDataList.Add(new StudentData(StudentName.Benny, Subject.Physic, 75));

    studentDataList.Add(new StudentData(StudentName.Nikki, Subject.History, 65));
    studentDataList.Add(new StudentData(StudentName.Nikki, Subject.Math, 70));
    studentDataList.Add(new StudentData(StudentName.Nikki, Subject.Physic, 75));

    studentDataList.Add(new StudentData(StudentName.Tom, Subject.History, 88));
    studentDataList.Add(new StudentData(StudentName.Tom, Subject.Math, 90));
    studentDataList.Add(new StudentData(StudentName.Tom, Subject.Physic, 95));

下面定義了因子表

        List<double> FactorTable = new List<double>();
        FactorTable.Add(1.05);
        FactorTable.Add(1.02);

我想要實現的是創建一個 Dictionary<StudentName, Double> ,該值存儲該學生的所有加權平均分數(乘以所有分數和因子列表)。 例如在本尼的情況下:

 Dictionary<StudentName, double> StudentDic = new Dictionary<StudentName, double>();

鍵:本尼,值:(85 * 1.05) + (85 * 1.02) + (60 * 1.05) + (60 * 1.02) + (75 * 1.05) + (75 * 1.02)

我認為它可以通過少數聚合 Linq 操作來完成。 然而,當我開始實施時,它並不那么容易實現。 我所做的如下:

            foreach (var student in studentName)
        {
            var filterStudent = studentDataList.Where(s => s.Name == student);

            List<double> multipledResult = new List<double>();

            foreach (var s in filterStudent)
            {
                foreach (var f in FactorTable)
                {
                    multipledResult.Add(s.Score * f);
                }
            }
            StudentDic.Add(student, multipledResult.Average());
        }

通過使用 Linq 操作來簡化算法,我錯過了什么。 有人可以建議是否有辦法改進它?

這應該給你一個起點:

var result = 
    studentDataList
    .SelectMany(sdl => FactorTable.Select(ft => new {
        sdl.Name, 
        aggScore = ft * sdl.Score
    }))
    .GroupBy(prod => prod.Name)
    .Select(g => new { 
        Name = (StudentName)g.Key, 
        wtAvg = g.Sum(x => x.aggScore) / g.Sum(x => x.ft)
    })
    .ToDictionary(x => (StudentName)x.Name, x => x.wtAvg);

SelectMany -> Select方法通過每個權重為您提供每個分數的目標產品。 然后鏈為每個人創建一個組。 最后的Select匯總了組中的所有加權產品。 如果您真的需要,最后一行會將其轉換為字典。

但不要忘記,對於加權平均,您還想除以可能的總權重。

它給出了結果:

| Benny | 73.333... |
| Nikki | 70        |
| Tom   | 91        |

本尼的分數基本上是通過以下方式得出的:

 var num = (85 * 1.05) + (85 *1.02) + (60 * 1.05) + (60 * 1.02) + (75 * 1.05) + (75 * 1.02);
 var den = 1.05 + 1.02 + 1.05 + 1.02 + 1.05 + 1.02;
 var result = num / den; // 73.33333......

當然,如果您真的想要加權總和,而不是加權平均值,那么只需刪除最終選擇方法中的分母並將其從wtAvg重命名為wtSum

正如@pwilcox 提到的, SelectMany是典型 LINQ 處理結果的關鍵,但我建議先分組,然后計算:

var StudentDic = studentDataList.GroupBy(s => s.Name, s => s.Score)
                                .ToDictionary(sg => sg.Key,
                                              sg => sg.SelectMany(s => FactorTable.Select(f => s*f)).Average());

請注意,您可以通過對學生的分數求和,將總和乘以每個因素,然后將總和除以分數計數乘以因素計數來避免SelectMany

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM