如何用LINQ按时间范围分组统计符合指定代码集的对象?
高效实现基于时间和人员的事件分组统计需求
需求说明
- 先按
PersonKey(人员标识)对TestData对象列表进行分组; - 每个分组内,筛选出
ActionCode匹配指定代码集的条目(代码顺序无要求); - 仅当该代码集对应的所有条目都处于60分钟的时间范围内时,才进行统计;
- 已被分组统计的事件(
EventKey)不再参与后续统计。
现有实现逻辑粗糙、效率低下,需要更高效的解决方案。
代码示例
public class TestData { public int PersonKey { set; get; } public int EventKey { set; get; } public string ActionCode { set; get; } public DateTime ActionDate { set; get; } } public static void DoSummary() { // 示例统计规则 var section1 = new { name = "Section 1", codes = new List<string>(new string[] { "code1", "code2" }) }; var section2 = new { name = "Section 2", codes = new List<string>(new string[] { "code1", "code3", "code4" }) }; var section3 = new { name = "Section 3", codes = new List<string>(new string[] { "code1", "code2", "code5" }) }; var list = new List<TestData>(); // 过滤出包含指定代码的条目 list = list.Where(x => section2.codes.Contains(x.ActionCode)).ToList(); for (int year = 2010; year < 2023; year++) { // 存储已统计过的事件ID,避免重复统计 var skipEvents = new List<int>(); // 筛选当前年份的数据 var yearData = list.Where(x => x.ActionDate.Year == year); // 按人员标识分组 var people_in_year = yearData.GroupBy(x => x.PersonKey); int count = 0; // 仅处理事件数大于1的人员分组 foreach (var g in people_in_year.Where(x => x.Count() > 1)) { foreach (var ev in g) { var testList = new List<int>(); bool allCodesFound = true; foreach (var otherCode in section1.codes.Where(x => x != ev.ActionCode)) { var found = g.Where(x => !skipEvents.Contains(x.EventKey) && x.ActionCode == otherCode && // 确保两个事件的时间差在60分钟内 (ev.ActionDate - x.ActionDate).TotalMinutes > -60 && (ev.ActionDate - x.ActionDate).TotalMinutes < 60 ).ToList(); if (found.Count > 0) { // 收集匹配到的事件ID,后续标记为已统计 testList.AddRange(found.Select(x => x.EventKey)); } else { allCodesFound = false; } } if (allCodesFound) { // 将匹配到的事件加入跳过列表,避免重复统计 skipEvents.AddRange(testList); count++; } } } } }
补充说明
一旦事件被分组统计,其EventKey将被标记,不再参与任何后续统计。
内容的提问来源于stack exchange,提问作者Andy Le
相关产品推荐
相关产品推荐

