如何使用LINQ筛选累加时长低于阈值的工时数据子集
LINQ实现低于工时阈值的记录子集筛选
问题场景
开发员工排班应用时,需要统计指定时间范围内,两类不同薪资类型的工时累加值低于2250分钟(即37.5小时)的记录。目前通过两次调用.Sum()分别计算两类薪资对应工时再累加的求和逻辑可正常运行,但无法正确筛选出符合总时长要求的记录子集,现有分组后的代码片段如下:
g.Sum(x => x.Start >= start && x.End <= End ? x.Type1 : 0) + g.Sum(x => x.Start >= start && x.End <= End ? x.Type2 : 0) <= 2250 ? ..... // then count the hours below here.
该逻辑在总时长超过2250分钟时会直接返回0,无法生成符合要求的工时数据子集。
问题原因
现有逻辑存在两个明显问题:
- 重复遍历分组内的记录做两次求和,存在不必要的性能损耗
- 没有将总时长阈值判断作为分组的过滤条件,仅通过三元表达式做分支返回,不符合阈值的分组会直接走返回0的分支,无法保留符合要求的完整记录子集
正确实现方式
按照「先过滤时间范围→再按维度分组→再按总工时阈值筛选合格分组→最后输出需要的子集/统计值」的顺序写LINQ即可,参考代码如下:
var validShiftSet = shiftDataSource // 第一步:先把不在指定时间范围内的记录全过滤掉,后续不需要重复判断时间区间 .Where(shift => shift.Start >= start && shift.End <= end) // 第二步:按你需要的维度分组,比如按员工ID、按周维度都可以,替换成实际的分组键即可 .GroupBy(shift => shift.EmployeeId) // 第三步:筛选出组内总工时低于阈值的分组 .Where(group => { int total = 0; foreach (var item in group) { total += item.Type1 + item.Type2; // 数据量较大时可以加提前终止逻辑,累加已经超阈值就直接跳过该组,不用算完所有记录 if (total > 2250) return false; } return total <= 2250; }) // 第四步:组装你需要的结果,既可以拿原始记录子集,也可以直接算统计值 .Select(group => new { GroupKey = group.Key, // 该分组下所有符合阈值要求的原始工时记录,就是你要的子集 ValidShiftRecords = group.ToList(), TotalMinutes = group.Sum(item => item.Type1 + item.Type2), TotalHours = Math.Round(group.Sum(item => item.Type1 + item.Type2) / 60.0, 2) }) .ToList();
如果不需要做提前终止的性能优化,也可以把第三步的筛选逻辑写成更简洁的形式:
.Where(group => group.Sum(item => item.Type1 + item.Type2) <= 2250)
注意:如果
Type1、Type2字段是可空数值类型,求和时需要写为(item.Type1 ?? 0) + (item.Type2 ?? 0),避免空引用引发报错。
内容的提问来源于stack exchange,提问作者Rowandinho
相关产品推荐
相关产品推荐

