LINQ 按日期和时间分组

问题描述 投票:0回答:1

我正在尝试从单元测试开始编写一个 linq 语句,该语句从一天中的一个小时开始按天对考试进行分组。

基本条件如下

1st exam with recording date 2024-03-21T11:20:00, Id = 3; 
2nd exam with recording date 2024-03-21T11:50:00, Id = 4; 
3rd exam with recording date 2024-03-21T12:20:00, Id = 5; 
4th exam with recording date 2024-03-21T12:50:00, Id = 6; 
5th exam with recording date 2024-03-22T11:20:00, Id = 7; 
6th exam with recording date 2024-03-22T11:50:00, Id = 8; 
7th exam with recording date 2024-03-22T12:20:00, Id = 9; 
8th exam with recording date 2024-03-23T12:50:00, Id = 10; 
9th exam with recording date 2024-03-23T11:20:00, Id = 11; 
10th exam with recording date 2024-03-23T11:50:00, Id = 12; 
11th exam with recording date 2024-03-23T12:20:00, Id = 13; 
12th exam with recording date 2024-03-23T12:50:00, Id = 24; 

如果按从中午开始的一天进行分组,则要达到的结果如下

1st visit with Id = 1 and exams with Id = [3, 4]
2nd visit with Id = 5 and exams with Id = [5, 6, 7, 8]
3rd visit with Id = 9 and exams with Id = [9, 10, 11, 12]
4th visit with Id = 13 and exams with Id = [13, 24]

或者如果按从中午开始的几天分组

1st visit with Id = 1 and exams with Id = [3, 4]
2nd visit with Id = 5 and exams with Id = [5, 6, 7, 8, 9, 10, 11, 12]
3rd visit with Id = 13 and exams with Id = [13, 24]

这是第一个测试简单条件的单元测试

[TestMethod]
public void Convert_TwoExamSplitAtNoon_TwoVisits()
{
    PatientWithExams p = new() { PatientId = 1 };

    p.Exams.Add(new LightExam()
    {
        ExamId = 1,
        ExamType = Micromed.Domain.Archive.Types.ExamFileTypeId.EegTrace,
        RecordingDate = new DateTime(2024, 3, 21, 11, 20, 00)
    });

    p.Exams.Add(new LightExam()
    {
        ExamId = 1,
        ExamType = Micromed.Domain.Archive.Types.ExamFileTypeId.EegTrace,
        RecordingDate = new DateTime(2024, 3, 21, 12, 20, 00)
    });

    List<PatientWithExams> patients = new() { p };

    TimeSpan splitTime = new(12, 00, 00);

    Dictionary<int, List<LightVisit>> visits = _converter.ConvertNew(patients, splitTime);

    // Assert
    Assert.AreEqual(true, visits[1].Count() == 2);
}

我能够编写将考试转换为访问的方法,但实际上我不考虑按小时休息

TimeSpan groupInterval = TimeSpan.FromDays(1);

var eegExams = from e in patient.Exams.Where(e => e.ExamType == Domain.Archive.Types.ExamFileTypeId.EegTrace)
               group e by e.RecordingDate.Ticks / groupInterval.Ticks into g
               select new { day = new DateTime(g.Key * groupInterval.Ticks), Values = g.Count(), Exams = g.DefaultIfEmpty() };

谢谢, 瑞克

c# linq unit-testing
1个回答
0
投票

您尝试做的是某种分箱或加窗,通常用于创建直方图。您有一个起点和所需的时间段或窗口长度(例如 1 天)。然后迭代所有元素并生成 bin/window id 并按此 id 对元素进行分组。这是一个代码示例,您可以根据需要采用:

public class Program
{
    static void Main(string[] args)
    {
        var now = DateTime.UtcNow;
        var items = Enumerable.Range(1, 10)
            .Select(i => new Item { Id = i, Occurence = now.AddHours(i * 5) })
            .ToList();

        var twelveHourWindows = items
            .GroupBy(item => GetWindow(item.Occurence, now));

        foreach (var group in twelveHourWindows)
        {
            Console.WriteLine($"Group id: {group.Key}");

            foreach (var item in group)
            {
                Console.WriteLine($"   {item.Id} {item.Occurence}");
            }
        }
    }

    private static DateTime GetWindow(DateTime occurence, DateTime start)
    {
        var diff = occurence - start;
        var steps = (int)Math.Floor(diff.TotalHours / 12);

        return start.AddHours(steps * 12);
    }
}

public class Item
{
    public int Id { get; set; }
    public DateTime Occurence { get; set; }
}

神奇的东西发生在

GetWindow()
方法内。该方法从当前项获取起始点和相应的值来计算所需的窗口 id 并返回窗口的值,该值应该用于该项。

希望这可以帮助您解决您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.