linq多行数据的时间比较

会议室aidname1会议室12会议室2会议室的预约bidstartdateenddateaID02015-1-19:002015-1-110:00112015-1-11... 会议室 a
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来写 这个怎么写阿?
展开
 我来答
makosharp
2015-05-31 · TA获得超过676个赞
知道小有建树答主
回答量:188
采纳率:100%
帮助的人:279万
展开全部

坦白说这个需求只会用到一点点Linq,也只应该适量使用Linq,因为Linq更多的是针对集合遍历和多集合互操作,并非在记录之间进行Aggregate聚合运算。


当然,只求结果的话Linq确实可以满足你的需求,只是代码会较为晦涩不易阅读。

这里使用了如下方式进行运算,找出所有会议室的空闲时间段。

  1. 对B表进行分组,依据是aID

  2. 对每一组根据时间升序排列

  3. 由于我们要做的事情是“用任意一条记录的startdate减去其前一条记录的enddate并判断时间是否多过三小时”,这里分别提取所有的startdate和enddate序列作为T1和T2。

  4. 在startdate序列T1前插入一个默认值9:00,在enddate序列T2后插入一个默认值18:00,如此我们得到了记录数目相等的序列T1'和T2'

  5. 使用Zip扩展方法合并两个序列,使T1'的每一条记录和T2'的对应记录(按元素顺序)做减法,得到时间差值和其他相关信息,结果作为序列C

  6. 判断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 广告
迈杰转化医学研究(苏州)有限公司于2013年成立,其前身为凯杰(苏州)转化医学研究有限公司。基于基因组学、蛋白组学、细胞组学及病理组学等综合性转化医学平台,丰富的伴随诊断开发经验,高质量的管理体系以及高素质的研发管理团队,迈杰转化医学为全球... 点击进入详情页
本回答由迈杰提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式