
linq多行数据的时间比较
id name
1 会议室1
2 会议室2
会议室的预约 b
id startdate enddate aID
0 2015-1-1 9:00 2015-1-1 10:00 1
1 2015-1-1 11:00 2015-1-1 12:00 1
2 2015-1-1 13:00 2015-1-1 18:00 1
3 2015-1-1 9:00 2015-1-1 12:00 2
4 2015-1-1 13:00 2015-1-1 15:00 2
我想查询 工作时间之内 早9晚6 在3个小时之内的空闲的会议室
以上面的数据为示例,会议室2的15:00-18:00就可以用.就把会议室2给查询出来
我想用linq来写 这个怎么写阿? 展开
坦白说这个需求只会用到一点点Linq,也只应该适量使用Linq,因为Linq更多的是针对集合遍历和多集合互操作,并非在记录之间进行Aggregate聚合运算。
当然,只求结果的话Linq确实可以满足你的需求,只是代码会较为晦涩不易阅读。
这里使用了如下方式进行运算,找出所有会议室的空闲时间段。
对B表进行分组,依据是aID
对每一组根据时间升序排列
由于我们要做的事情是“用任意一条记录的startdate减去其前一条记录的enddate并判断时间是否多过三小时”,这里分别提取所有的startdate和enddate序列作为T1和T2。
在startdate序列T1前插入一个默认值9:00,在enddate序列T2后插入一个默认值18:00,如此我们得到了记录数目相等的序列T1'和T2'
使用Zip扩展方法合并两个序列,使T1'的每一条记录和T2'的对应记录(按元素顺序)做减法,得到时间差值和其他相关信息,结果作为序列C
判断C中有无空闲时间大于等于三小时的记录,若有,说明C所属的分组(见步骤1)所使用的会议室有空闲时间段
代码如下,包含了你提供的样例数据。
最终输出的结果集是匿名类{availableStart,availableEnd,availableHours,availableConferenceRoomName}的实例的集合,每个实例都代表了“某个会议室从某时间起到某时间结束可用,可用时间为XXX”。
9:00,18:00,3小时这三个可变值都已被参数化,请自行修改测试。
var ConferenceRooms = new[]
{
new{id=1,name="会议室1"},
new{id=2,name="会议室2"}
};
var Reservations = new[]
{
new{id=0,startdate=DateTime.Parse("2015-1-1 9:00"),enddate=DateTime.Parse("2015-1-1 10:00"),aID=1},
new{id=1,startdate=DateTime.Parse("2015-1-1 11:00"),enddate=DateTime.Parse("2015-1-1 12:00"),aID=1},
new{id=2,startdate=DateTime.Parse("2015-1-1 13:00"),enddate=DateTime.Parse("2015-1-1 18:00"),aID=1},
new{id=3,startdate=DateTime.Parse("2015-1-1 9:00"),enddate=DateTime.Parse("2015-1-1 12:00"),aID=2},
new{id=4,startdate=DateTime.Parse("2015-1-1 13:00"),enddate=DateTime.Parse("2015-1-1 15:00"),aID=2}
};
//Let's rock N roll!
var minTime = DateTime.Parse("2015-1-1 9:00");
var maxTime = DateTime.Parse("2015-1-1 18:00");
var hoursRequired = 3.0;
var availableConferenceRoom = Reservations
.Where(r => r.startdate >= minTime && r.enddate <= maxTime)
.GroupBy(r => r.aID)
.SelectMany(group => group
.Select(g => new { start = g.startdate })
.Concat(new[] { new { start = maxTime } })
.OrderBy(g => g.start)
.Zip(group
.Select(g => new { end = g.enddate })
.Concat(new[] { new { end = minTime } })
.OrderBy(g => g.end),
(t1, t2) => new
{
availableStart = t2.end,
availableEnd = t1.start,
availableHours = t1.start.Subtract(t2.end).TotalHours,
availableConferenceRoomName = ConferenceRooms.First(c => c.id == group.Key).name })
.Where(c => c.availableHours >= hoursRequired))
.ToList();
如果我们删除id=2的记录测试,可以看到输出结果是
{availableStart={2015-1-1 12:00:00}, availableEnd={2015-1-1 18:00:00}, availableHours=6.0, availableConferenceRoomName="会议室1"}
和
{availableStart={2015-1-1 15:00:00}, availableEnd={2015-1-1 18:00:00},
availableHours=3.0, availableConferenceRoomName="会议室2"}
不用怀疑,这真的只是一条语句,虽然我个人强烈建议不要这样写。(想拿去秀技术的除外>.<)
原因有2:难以理解;无法调试。
对于你的需求,使用以下代码会更加合适:
var result = new List<Tuple<DateTime, DateTime, double, string>>();
var groupedRecords = Reservations.GroupBy(rec => rec.aID);
foreach (var g in groupedRecords)
{
var aID = g.Key;
var roomName = ConferenceRooms.First(c => c.id == aID).name;
var records = g.OrderBy(rec => rec.startdate).ToList();
for (int recordIndex = 0; recordIndex < records.Count; recordIndex++)
{
//if this is the first record in the group, compare its startdate and 9:00
if (recordIndex == 0)
{
var firstRecord = records[recordIndex];
if (firstRecord.startdate >= minTime.AddHours(hoursRequired))
{
result.Add(new Tuple<DateTime, DateTime, double, string>(minTime, firstRecord.startdate, firstRecord.startdate.Subtract(minTime).TotalHours, roomName));
}
}
//if this is the last record in the group, compare its enddate and 18:00
else if (recordIndex == records.Count - 1)
{
var lastRecord = records[recordIndex];
if (maxTime >= lastRecord.enddate.AddHours(hoursRequired))
{
result.Add(new Tuple<DateTime, DateTime, double, string>(lastRecord.enddate, maxTime, maxTime.Subtract(lastRecord.enddate).TotalHours, roomName));
}
}
//otherwise,compare current record's enddate and the next record's startdate
else
{
var currentRecord = records[recordIndex];
var nextRecord = records[recordIndex + 1];
if (nextRecord.startdate.Subtract(currentRecord.enddate).TotalHours >= hoursRequired)
{
result.Add(new Tuple<DateTime, DateTime, double, string>(currentRecord.enddate, nextRecord.startdate, nextRecord.startdate.Subtract(currentRecord.enddate).TotalHours, roomName));
}
}
}
}
//print your result
结果和上面的一句话Linq是一样的。可以看到代码虽然多了不少,但是逻辑清晰有条理,方便修改和调试。这里不讨论效率,因为两者算法不一样。

2024-11-30 广告