C#统计申请人项目平均评分时重入项目0值计入异常问题
问题根因
原代码逻辑有两个核心问题:
- 计算评分时没有按项目维度去重,申请人多次进出同一个项目时,
participants里会生成多条同项目的参与记录 - 原逻辑直接筛出所有
Rating>0的记录算平均,没有对同项目的多条记录做有效性校验,重进项目生成的初始0值记录会因为数据重复、历史记录状态异常等问题被错误纳入计算。
另外你贴的代码里PreviousPrograms赋值那行最后写的.ToList(p => p.ProgramName)是语法错误,LINQ的ToList()没有带选择器的重载,这段代码无法正常编译。
修复方案
核心调整评分计算逻辑:先按项目分组,每个项目只取最新的一条参与记录,再过滤掉0值的无效评分计算平均值,同时修复现有语法问题、给项目列表加去重避免重复展示,修复后的完整代码如下:
public async Task<T> GetAllApplicants() { // 原有其他逻辑 IList<T> participants = await GetAllParticipants(); // applicants 原有赋值逻辑保留 foreach (var applicant in applicants) { // 提前筛选当前申请人的所有参与记录,减少重复遍历 var userParticipantList = participants .Where(p => p.Email.EqualsIgnoreCase(applicant.Email)) .ToList(); // 取所有参与项目,加Distinct避免同项目多次进出重复展示 applicant.Programs = userParticipantList .Select(p => p.ProgramName) .Distinct() .ToList(); // 修复原ToList的语法错误,同样加去重 applicant.PreviousPrograms = userParticipantList .Where(p => p.IsPreviousParticipant) .Select(p => p.ProgramName) .Distinct() .ToList(); applicant.AverageRating = userParticipantList // 按项目名分组,同一个项目只统计一次 .GroupBy(p => p.ProgramName) // 每组取最新的参与记录:优先取当前在参与的非历史记录 .Select(g => g.OrderBy(p => p.IsPreviousParticipant).First()) // 过滤掉0值的未评分记录 .Where(p => p.Rating > 0) .Select(p => p.Rating) // 无有效评分时默认值3 .DefaultIfEmpty(3) .Average() .ToDouble(); } return applicants; }
补充说明
如果你的参与记录实体存了加入时间/创建时间字段(比如JoinTime、CreateOn),建议把分组后取最新记录的逻辑改成按时间倒序,比靠IsPreviousParticipant判断更准确,替换写法如下:
.Select(g => g.OrderByDescending(p => p.JoinTime).First())
调整后不管申请人同一个项目进出多少次,都只会取最后一次参与的最新评分,未录入有效评分的初始0值会被直接过滤,不会再出现错误计入平均的问题。
内容的提问来源于stack exchange,提问作者DonDavid12
相关产品推荐
相关产品推荐

