c# - 遍历 IEnumerable 并按日期和时间跨度差异分组

标签 c# linq

我有一个从 LINQ 查询创建的 IEnumerable 对象。

数据看起来像这样:

Id        EventName        EventDate        EventStart      EventEnd
--------------------------------------------------------------------
1        StoryTime          4/6/2018        8:00            8:45        
2        Baking             4/6/2018        8:55            9:30
3        Cooking            4/7/2018        7:45            9:50
4        Comprehension      4/8/2018        9:05            10:10
5        WindDown           4/8/2018        10:25           10:55
6        Naptime            4/8/2018        11:00           11:30
7        Play               4/8/2018        13:50           14:20
8        Smarts             4/8/2018        14:30           16:00
9        StoryTime          4/9/2018        9:30            12:05
10       FunTime            4/10/2018       14:10           16:10

我需要遍历 IEnumerable 并通过检查日期和时间来检查数据。我想将同一天发生的事件组合在一起,并且事件的 EventStart 时间与之前的事件 EventEnd 时间相差不超过 30 分钟。

逻辑很复杂。我一直在尝试不同的事情,但找不到任何方法。

这是我到目前为止的进展:

// loop through IEnumerable object created with linq query
foreach (var e in eventResults)
{
    // set current interation current date
    DateTime? currentDate = e.EventDate;

    // make sure we are only checking time span differences in the same day
    while (e.EventDate == currentDate)
    {
         int currentId = e.Id;
         DateTime? currentStartTime = e.EventStart;
         DateTime? currentEndTime = e.EventEnd; 

        // stuck -- not sure where to go with my logic  :(
    }
}

当一切都完成后,它看起来像这样:

  • 4 月 6 日,故事时间 + 烘焙:8:00 - 9:30
  • 4 月 7 日, cooking :7:45 - 9:50
  • 4 月 8 日,理解 + 放松 + 午睡:9:05 - 11:30
  • 4 月 8 日,Play + Smarts:13:50 - 16:00
  • 4 月 9 日,StoryTime:9:30 - 12:05
  • 4 月 10 日,FunTime:14:10 - 16:10

如果有人能提供一些帮助,我将不胜感激。谢谢!

最佳答案

这里有一些 linq 方法,使用 group by day 和 Aggregate 在每一天创建动态子组(实际上是列表):

var eventResults = new[]
{
    new EventItem(1, "StoryTime", new DateTime(2018, 4, 6), new TimeSpan(8, 0, 0), new TimeSpan(8, 45, 0)),
    new EventItem(2, "Baking", new DateTime(2018, 4, 6), new TimeSpan(8,55, 0), new TimeSpan(9, 30, 0)),
    new EventItem(3, "Cooking", new DateTime(2018, 4, 7), new TimeSpan(7,45, 0), new TimeSpan(9, 50, 0)),
    new EventItem(4, "Comprehension", new DateTime(2018, 4, 8), new TimeSpan(9, 5, 0), new TimeSpan(10,10, 0)),
    new EventItem(5, "WindDown", new DateTime(2018, 4, 8), new TimeSpan(10,25, 0), new TimeSpan(10,55, 0)),
    new EventItem(6, "Naptime", new DateTime(2018, 4, 8), new TimeSpan(11,0, 0), new TimeSpan(11,30, 0)),
    new EventItem(7, "Play", new DateTime(2018, 4, 8), new TimeSpan(13,50,0), new TimeSpan(14,20, 0)),
    new EventItem(8, "Smarts", new DateTime(2018, 4, 8), new TimeSpan(14,30,0), new TimeSpan(16, 0, 0)),
    new EventItem(9, "StoryTime", new DateTime(2018, 4, 9), new TimeSpan(9,30, 0), new TimeSpan(12, 5, 0)),
    new EventItem(10, "FunTime", new DateTime(2018, 4, 10), new TimeSpan(14,10,0), new TimeSpan(16,10, 0)),
};
var groups = eventResults
    .GroupBy(x => x.EventDate)
    .SelectMany(g => g.OrderBy(x => x.EventStart)
        .Aggregate(new List<List<EventItem>> { new List<EventItem>() }, (l, e) =>
        {
            if ((e.EventStart - l.Last().Select(x => x.EventEnd).DefaultIfEmpty(e.EventStart).Last()).TotalMinutes <= 30)
            {
                l.Last().Add(e);
            }
            else
            {
                l.Add(new List<EventItem> { e });
            }
            return l;
        })
        .Select(x =>
        new
        {
            Date = g.Key,
            activities = x
        }))
    .OrderBy(x => x.Date).ThenBy(x => x.activities.First().EventStart);

foreach (var item in groups)
{
    var activities = string.Join(" + ", item.activities.Select(x => x.EventName));
    Console.WriteLine($"On {item.Date}, {activities}: {item.activities.First().EventStart} - {item.activities.Last().EventEnd}");
}

关键是,当条目之间的距离小于 X 时,要求分组不是一个合适的分组条件。因此,需要对每天的(排序的)条目进行某种迭代。

在这里,我并不特别提倡在传统循环中使用聚合。这就是我决定编写代码的方式。编写循环代码可能对初学者更友好(更易于阅读)。

关于c# - 遍历 IEnumerable 并按日期和时间跨度差异分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53270578/

相关文章:

c# - 生成订单号

c# - 如何单元测试级联删除 Entity Framework 中的实体?

c# - 从 HashTable 键创建一个 List<string>?

c# - linq to entities dynamic where 从 lambdas 构建

c# - 从数据库中获取字段值的动态 LINQ 查询

c# - MYSQL 获取日期列作为字符串

c# - 将 Serilog 与 Azure 日志流结合使用

c# - LINQ 中按子表分组

c# - 如何将用户输入的字符串作为字段名传递以访问对象中的字段?

c# - 对可为空值的多个可能组合执行 Linq 操作