如何计算员工指定门禁区域停留时长?(避免嵌套循环判断)
数据背景
现有存储于eventList中的GateEvent对象列表,每个对象包含以下属性:
Employee:员工信息(每位员工对应唯一门禁权限)GateTitle:门禁名称Timestamp:事件时间戳InsidePremises:是否在目标区域内EntryGranted:门禁通行是否被允许(仅通过指定门禁时为true)
权限与状态规则
- 员工仅能通过指定门禁(如示例中John Doe仅可通过
Assembly line门禁),尝试非指定门禁时EntryGranted返回false - 通过指定门禁且
InsidePremises从true变为false时,表示员工离开区域;首次进入指定门禁时无前置状态,直接标记为true - 非指定门禁的通行尝试不改变员工的
InsidePremises状态
示例代码与输出
遍历事件列表代码
foreach(GateEvent x in eventList) { Console.WriteLine($"{x.Employee} | {x.GateTitle} | {x.Timestamp} | {x.EntryGranted} | {x.InsidePremises}"); }
遍历输出示例
...
John Doe | Assembly line | 2022-10-06 08:51:27 | true | true // 进入区域
John Doe | Sales office | 2022-10-06 09:41:07 | false | true // 无法通行,仍在Assembly line区域
John Doe | Assembly line| 2022-10-06 10:00:08 | true | false // 离开区域
John Doe | Sales office | 2022-10-06 10:10:05 | false | false // 无法通行,不在工作区域
John Doe | Assembly line | 2022-10-06 11:53:00 | true | true // 再次进入区域
John Doe | Management | 2022-10-06 12:00:00 | false | true // 无法通行,仍在Assembly line区域
John Doe | Assembly line | 2022-10-06 14:03:40 | true | false // 离开区域
...
需求目标
计算员工在Assembly line区域的单次停留时长(即每个InsidePremises=true到false的时间区间时长),要求避免在for循环中使用嵌套if语句实现。
实现方案(C#)
利用LINQ链式调用,通过分组、筛选、配对事件的方式实现,全程无嵌套if:
// 按员工分组,筛选指定门禁的有效通行记录并计算停留时长 var employeeStayDetails = eventList // 只保留Assembly line门禁的有效通行事件 .Where(e => e.GateTitle == "Assembly line" && e.EntryGranted) // 按员工分组 .GroupBy(e => e.Employee) .Select(group => new { EmployeeName = group.Key, // 对当前员工的事件按时间排序,配对进入/离开事件计算时长 StayRecords = group.OrderBy(e => e.Timestamp) .Select((evt, idx) => new { Event = evt, Index = idx }) // 仅取偶数索引的进入事件(对应下一个奇数索引的离开事件) .Where(pair => pair.Index % 2 == 0 && pair.Index + 1 < group.Count()) .Select(pair => { var enterEvent = pair.Event; var leaveEvent = group.OrderBy(e => e.Timestamp).ElementAt(pair.Index + 1); return new { EnterTime = enterEvent.Timestamp, LeaveTime = leaveEvent.Timestamp, Duration = leaveEvent.Timestamp - enterEvent.Timestamp }; }) }); // 输出计算结果 foreach(var employeeData in employeeStayDetails) { Console.WriteLine($"员工: {employeeData.EmployeeName}"); foreach(var record in employeeData.StayRecords) { Console.WriteLine($"进入时间: {record.EnterTime}, 离开时间: {record.LeaveTime}, 停留时长: {record.Duration}"); } }
方案说明
- 先过滤掉非指定门禁、通行失败的无效事件,只保留有效通行记录
- 按员工分组后,对每个员工的事件按时间排序
- 通过索引奇偶性自动配对进入(偶数位)和离开(奇数位)事件,直接计算时间差
- 全程使用LINQ链式调用替代传统循环嵌套,避免了冗余的条件判断
内容的提问来源于stack exchange,提问作者Justas Xibu

