我有一个问题,我需要根据时间属性查找(分组)对象列表。
我需要先按一个属性(人员 ID/键)进行分组,然后在该组中找到另一个属性与代码集匹配(以任何顺序)的条目,最后只计算是否在彼此的时间范围内找到该代码集(在这个例子中是 60 分钟)。
下面我已经很粗暴地尝试这样做了,我知道它一定是非常低效的。
感谢观看
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()
{
//sample criteria
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>();
//filter original list to only include those containing certain codes
list = list.Where(x => section2.codes.Contains(x.ActionCode)).ToList();
for (int year = 2010; year < 2023; year++)
{
//storing already counted items to not count multiple times
var skipEvents = new List<int>();
//getting the year's data just to make things easier/more managable
var yearData = list.Where(x => x.ActionDate.Year == year);
//group by the person key
var people_in_year = yearData.GroupBy(x => x.PersonKey);
int count = 0;
//only check those that have more than one event in the people group
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 &&
//in case the current event date is before the checked date in the list
(ev.ActionDate - x.ActionDate).TotalMinutes > -60 &&
(ev.ActionDate - x.ActionDate).TotalMinutes < 60
).ToList();
if (found.Count > 0)
{
//add the event keys to allow skipping later if all matched
testList.AddRange(found.Select(x => x.EventKey));
}
else
{
allCodesFound = false;
}
}
if (allCodesFound)
{
//add all the keys already found to skip later on as they already have been grouped
skipEvents.AddRange(testList);
count++;
}
}
}
}
}
编辑(澄清):一旦事件被分组,就不应再考虑它。
这是一个示例应用程序,小提琴:https://dotnetfiddle.net/sCHti6
检查它是否做了它应该做的事情。
using System;
using System.Collections.Generic;
using System.Linq;
public class TestData
{
public int PersonKey { get; set; }
public int EventKey { get; set; }
public string ActionCode { get; set; }
public DateTime ActionDate { get; set; }
}
public class Program
{
public static void Main()
{
// Sample data
var testData = new List<TestData>
{
new TestData { PersonKey = 1, EventKey = 1, ActionCode = "code1", ActionDate = new DateTime(2023, 1, 1, 10, 0, 0) }, //This is match
new TestData { PersonKey = 1, EventKey = 2, ActionCode = "code3", ActionDate = new DateTime(2023, 1, 1, 10, 30, 0) }, //This is match
new TestData { PersonKey = 1, EventKey = 3, ActionCode = "code4", ActionDate = new DateTime(2023, 1, 1, 11, 0, 0) },
new TestData { PersonKey = 1, EventKey = 4, ActionCode = "code1", ActionDate = new DateTime(2023, 1, 1, 12, 0, 0) }, //This is match
new TestData { PersonKey = 1, EventKey = 5, ActionCode = "code3", ActionDate = new DateTime(2023, 1, 1, 12, 30, 0) }, //This is match
new TestData { PersonKey = 1, EventKey = 6, ActionCode = "code4", ActionDate = new DateTime(2023, 1, 1, 13, 0, 0) },
new TestData { PersonKey = 1, EventKey = 7, ActionCode = "code2", ActionDate = new DateTime(2023, 1, 1, 14, 0, 0) },
new TestData { PersonKey = 1, EventKey = 8, ActionCode = "code1", ActionDate = new DateTime(2023, 1, 1, 15, 0, 0) },
new TestData { PersonKey = 2, EventKey = 9, ActionCode = "code2", ActionDate = new DateTime(2023, 1, 1, 15, 30, 0) },
new TestData { PersonKey = 2, EventKey = 10, ActionCode = "code5", ActionDate = new DateTime(2023, 1, 1, 16, 0, 0) },
new TestData { PersonKey = 2, EventKey = 11, ActionCode = "code2", ActionDate = new DateTime(2023, 1, 1, 16, 30, 0) }
};
int count = CalculateEventCombinationsCount(testData);
Console.WriteLine($"Total count: {count}");
}
public static int CalculateEventCombinationsCount(List<TestData> list)
{
// Sample criteria
var section2 = new { name = "Section 2", codes = new List<string>(new string[] { "code1", "code3" }) };
int count = 0;
for (int year = 2023; year <= 2023; year++)
{
// Group by the person key
var people_in_year = list.Where(x => x.ActionDate.Year == year && section2.codes.Any(code => x.ActionCode == code))
.GroupBy(x => x.PersonKey);
foreach (var personGroup in people_in_year)
{
var events = personGroup.ToList();
for (int i = 0; i < events.Count - 1; i++)
{
// Filter remaining events within the time range of the current event
var foundEvent = events.Skip(i + 1).FirstOrDefault(x => (x.ActionDate - events[i].ActionDate).TotalMinutes >= 0 && (x.ActionDate - events[i].ActionDate).TotalMinutes < 60);
if (foundEvent!=null) count++; //Here you can debug the pair - events[i] and foundEvent is the pair
}
}
}
return count;
}
}