c# - 遍历 IEnumerable 并按日期和时间跨度差异分组
问题描述
我有一个从 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 日,StoryTime + 烘焙:8:00 - 9:30
- 4月7日,烹饪:7:45 - 9:50
- 4月8日,理解+放松+午睡:9:05 - 11:30
- 4月8日,Play + Smarts:13:50 - 16:00
- 4月9日,故事时间:9:30 - 12:05
- 4/10,欢乐时光:14:10 - 16:10
如果有人可以提供一些帮助,我将不胜感激。谢谢!
解决方案
这是一些 linq 方法,每天分组并在每天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
相距时对条目进行分组的要求不是一个合适的分组条件。因此,每天需要对(排序的)条目进行某种迭代。
我在这里并不特别提倡在传统循环上使用 Aggregate。这就是我决定编写这个东西的方式。编码循环可能对初学者更友好(更容易阅读)。
推荐阅读
- swift - 来自字典的 CLBeacon 的 RSSI 返回 nil
- android - 对讲开启时如何检测按下的软键盘
- php - 父类中存在属性时Laravel未定义属性错误
- java - Spring MockMvc 测试:Swagger allowableValues 不过滤错误参数
- javascript - 如何验证数组中的字母是否重复?
- postgresql - 无法以特定的数据库状态重新启动 Fusionauth
- java - JavaFX 使 ListView 在触摸屏上可滚动
- javascript - 事件处理匿名方法中的javascript分配
- c++ - 在 C++ 中前向声明模板变量
- django - 无需迭代即可通过关系查询 Django 多对多?