C#中是否有类似Excel的MINIF函数用于DataTables时间计算?
在C#中实现类似Excel MINIF的功能(筛选晚于指定时间的最小时间值)
C#没有内置的MINIF函数,但可以用LINQ快速实现相同效果,代码简洁且无需手动写遍历逻辑;如果数据量极大,还可以用二分查找进一步优化效率。
基础实现(适用于大多数场景)
针对你的DataTable工时核算场景,假设要筛选出指定确认编号下,晚于当前时间的最小打卡时间(Clock In/Clock Out均可),可以这样写:
// 假设你的DataTable实例为timeRecords int targetId = 500013; DateTime currentTime = new DateTime(2024, 1, 1, 8, 0, 0); // 示例起始时间 double totalHours = 0; int overlapCount = 2; // 初始重叠数 // 提取目标编号的所有打卡时间(合并Clock In和Clock Out) var targetTimes = timeRecords.AsEnumerable() .Where(row => row.Field<int>("确认编号") == targetId) .Select(row => new[] { row.Field<DateTime>("Clock In"), row.Field<DateTime>("Clock Out") }) .SelectMany(times => times); // 找到晚于currentTime的最小时间 DateTime? nextMinTime = targetTimes .Where(time => time > currentTime) .DefaultIfEmpty() .Min(); if (nextMinTime.HasValue) { // 计算时段时长并累加工时 TimeSpan duration = nextMinTime.Value - currentTime; totalHours += duration.TotalHours / overlapCount; // 更新状态,继续后续计算 currentTime = nextMinTime.Value; overlapCount = 3; }
高效优化(数据量极大时)
如果打卡记录量级很大,LINQ的Where+Min本质是全量遍历(O(n)复杂度),可以提前将时间排序后用二分查找(O(log n)复杂度)提升效率:
// 提前提取并排序目标编号的所有打卡时间 var sortedTargetTimes = timeRecords.AsEnumerable() .Where(row => row.Field<int>("确认编号") == targetId) .Select(row => new[] { row.Field<DateTime>("Clock In"), row.Field<DateTime>("Clock Out") }) .SelectMany(times => times) .OrderBy(t => t) .ToList(); // 用BinarySearch找第一个大于currentTime的时间 int index = sortedTargetTimes.BinarySearch(currentTime); if (index < 0) { index = ~index; // 转换为插入位置,即第一个大于目标时间的元素索引 if (index < sortedTargetTimes.Count) { DateTime nextMinTime = sortedTargetTimes[index]; // 后续工时计算逻辑 } }
关键说明
DefaultIfEmpty()用于避免无符合条件时间时Min()抛出异常,此时会返回DateTime.MinValue;若需要返回null,可将变量类型改为DateTime?并调整逻辑。- 二分查找仅适用于已排序的数据集,适合需要多次查询同一数据集的场景,提前排序一次即可复用多次查询。
内容的提问来源于stack exchange,提问作者James Patrick-Gleed
相关产品推荐
相关产品推荐

