如何不使用循环计算List中5000名员工的有效打卡进出时长
员工打卡数据匹配高效计算方案咨询
基础场景说明
- 数据流转路径:原始打卡CSV上传至数据库后,调用存储过程对数据做格式化处理,最终存入
EntryAndExit表,表内存储字段包含员工编号、EntryTime、EntryPoint、ExitTime、ExitPoint、Flag处理标记位,全量数据覆盖5000名员工一周的所有进出打卡记录 - 业务匹配规则:因员工会随机刷所有办公门进出,无固定进出通道顺序,需要为每个员工匹配出每轮进出的「首次EntryTime、对应EntryPoint」,以及和该EntryTime时间差不超过14小时的「末次ExitTime、对应ExitPoint」
- 现有实现的问题:
- 目前采用foreach嵌套while循环逐行遍历的方式做匹配,单员工定位符合要求的ExitTime时最多要遍历40条记录,全量数据处理耗时过长
- 每轮匹配完成后,需要把已参与计算的行的
Flag字段标记为1,后续过滤移除这些已处理行,避免重复计算 - 具体判定逻辑:取员工当前未处理的最早EntryTime作为本轮匹配起点,逐笔校验后续ExitTime和EntryTime的时间差,当出现时间差超过14小时的记录时,停止本轮匹配,取之前时间差在14小时内的最后一条ExitTime作为本轮的匹配退出记录,再开启下一轮新的EntryTime匹配。举个实际匹配例子:某员工某轮匹配的EntryTime为
2021-02-07 00:00:00,后续逐笔校验ExitTime时,直到第40条ExitTime记录(值为2021-02-07 07:08:06)才符合14小时内的要求;该记录之后的下一条ExitTime为2021-02-11 06:18:37,和EntryTime的时间差远超14小时,就会终止本轮匹配,开启下一轮新的EntryTime计算。
现有核心低效代码片段
int count = 0; DateTime entryTime = DateTime.Now; DateTime exitTime = DateTime.Now; TimeSpan difference = new TimeSpan(); double maxHour = 0; DateTime exitTimeLastIndex = DateTime.Now; foreach (var empId in employeeNumberList) { var maxRow = listEntryAndExit.AsEnumerable().Where(f => f.EmployeeNumber == empId && f.Flag == null).Count(); var query = listEntryAndExit.AsEnumerable().Where(f => f.EmployeeNumber == empId).OrderBy(f => f.EntryTime); while (count < maxRow) { while (count < maxRow) { if (count == 0) { // 取当前未处理的最早EntryTime作为本轮匹配的起始时间 var queryEntryTime = listEntryAndExit.AsEnumerable().Where(f => f.EmployeeNumber == empId); entryTime = queryEntryTime.AsEnumerable().OrderBy(x => x.EntryTime).Select(x => x.EntryTime).FirstOrDefault(); } var queryExitTime = query.ElementAt(count); if (queryExitTime != null) difference = queryExitTime.ExitTime.Subtract(entryTime); maxHour = difference.TotalHours; if (maxHour > 14) { break; } if (maxHour < 14) { if (queryExitTime != null) exitTimeLastIndex = queryExitTime.ExitTime; // 将匹配到的ExitTime对应行标记为已处理 var listUpdateEntryAndExit = listEntryAndExit.AsEnumerable().Where(f => f.EmployeeNumber == empId && f.ExitTime == exitTimeLastIndex).FirstOrDefault(); if (listUpdateEntryAndExit != null) { listUpdateEntryAndExit.Flag = 1; } } count++; } count = 0; Console.WriteLine($"Employee Number: {empId} | Entry Time: {entryTime} | Exit Time: {exitTimeLastIndex}"); // 移除已标记处理的行,缩小后续计算范围 var deleteRows = listEntryAndExit.RemoveAll(f => f.Flag == 1); maxRow = listEntryAndExit.AsEnumerable().Where(x => x.EmployeeNumber == empId && x.Flag == null).Count(); } }
核心诉求
寻找无需嵌套循环逐行遍历的List批量计算方案,大幅降低5000名员工一周打卡数据的处理耗时。
内容的提问来源于stack exchange,提问作者Yajnos
相关产品推荐
相关产品推荐

