C#从linq group by中获取分钟号

时间:2015-05-15 08:28:43

标签: c# linq datetime group-by

我需要按一天中的每一分钟对数据进行分组,并获取该分钟内发生的事件的计数。我目前有:

                items.GroupBy(x => new
                {
                    x.date.Minute,
                    x.date.Hour
                })
                .Select(x => new TransferObject
                {
                    Minute = x.Key.Minute,
                    Hour = x.Key.Hour,
                    Count = x.Count(),
                    Day = date
                }).OrderBy(x => x.Hour).ThenBy(x => x.Minute).ToList();

这就是我需要的,但问题是我可能没有每分钟的数据点,如果我没有那段时间的数据,我怎么能在Count字段中添加0?或者,我可以添加分钟号(0 ... 1440)并稍后添加缺失值。

修改

解决方案目前仅按开始日期分组,但该对象实际上有一个字段end_date。所以基本上目前我已经完成了那一分钟开始的所有事件,但我需要得到那一分钟正在运行的事件的数量。

我的数据包含:

date                    end_date
2015-05-15 09:52:15.650 2015-05-15 09:55:38.097
2015-05-15 09:52:15.633 2015-05-15 09:52:16.097
2015-05-15 09:52:11.633 2015-05-15 09:52:13.047
2015-05-15 09:51:49.097 2015-05-15 09:55:17.687
2015-05-15 09:51:49.087 2015-05-15 09:56:17.510

目前它不使用end_date字段,因此输出为

{Count:2;Hour:9;Minute:51}  
{Count:3;Hour:9;Minute:52}  

我需要运行所有正在运行的事件,例如

{Count:2;Hour:9;Minute:51}  
{Count:5;Hour:9;Minute:52}
{Count:3;Hour:9;Minute:53}
{Count:3;Hour:9;Minute:54}
{Count:3;Hour:9;Minute:55}
{Count:2;Hour:9;Minute:56}

3 个答案:

答案 0 :(得分:4)

看起来,您希望GroupJoin()而不仅仅是GroupBy(),类似的东西:

  var source = ... // Your query;

  var result = Enumerable
    .Range(0, 1440) // All the minutes that should be in the result
    .GroupJoin(source, 
       minutes => minutes, 
       item => item.Hour * 60 + item.Minute,
       (minutes, items) => new {
          hour = minutes / 60,
          minute = minutes % 60,
          count = items.Count() } ); // Count() can well return 0...

答案 1 :(得分:2)

首先,你可以产生所有时间和时间。一天中的几分钟使用一些简单的LINQ:

var all = Enumerable.Range(0,24)
                    .SelectMany(x => Enumerable.Range(0,60),
                                (x,y) => new {Hr = x, Min=y});
foreach(var a in all)
    Console.WriteLine("{0}:{1}",a.Hr,a.Min); // 00:00 thru 23:59

实例:http://rextester.com/NPNKN82691

然后,您可以使用此集合加入原始结果以形成最终输出:

var all = Enumerable.Range(0,24)
                    .SelectMany(x => Enumerable.Range(0,60),
                               (x,y) => new {Hr = x, Min=y});

var items = new[]{
        new Item{Date = new DateTime(2015,01,01,0,1,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0)},
        new Item{Date = new DateTime(2015,01,01,0,3,0)}
};

var results = all.GroupJoin(items,
                            x => new {Hour = x.Hr,Minute = x.Min},
                            y => new {Hour = y.Date.Hour,Minute = y.Date.Minute},
                            (x,y) => new {Hour = x.Hr, Minute = x.Min, Count = y.Count()});

foreach(var result in results)
   Console.WriteLine("{0:00}:{1:00} = {2}",result.Hour, result.Minute, result.Count);

输出

  

00:00 = 0
  00:01 = 6
  00:02 = 0
  00:03 = 1
  00:04 = 0
  //..snip..//
  23:55 = 0
  23:56 = 0
  23:57 = 0
  23:58 = 0
  23:59 = 0

实例http://rextester.com/OAYZ95244

修改

考虑到您考虑范围日期的要求的更改,您可以添加用于推断小时和时间的新类和方法。每个项目的分钟:

 // classes used
 public class ExtrapolatedItem
 {
     public int Hour{get;set;}
     public int Minute{get;set;}
 }

public class Item{
    public DateTime Date{get;set;}
    public DateTime EndDate{get;set;}
}

// method 

private static IEnumerable<ExtrapolatedItem> Extrapolate(Item item)
{
    for(var d = item.Date;d<=item.EndDate; d = d.AddMinutes(1))
    {
        yield return new ExtrapolatedItem{ Hour = d.Hour, Minute = d.Minute};
    }
}

然后可以在原始方法中使用它:

var items = new[]{
        new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)},
        new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)},
        new Item{Date = new DateTime(2015,01,01,0,3,0),EndDate = new DateTime(2015,1,1,0,5,0)}
};
var results = all.GroupJoin(items.SelectMany(Extrapolate), // extrapolate each item to a list of extrapolated items
                            x => new {Hour = x.Hr,Minute = x.Min},
                            y => new {Hour = y.Hour,Minute = y.Minute},
                            (x,y) => new {Hour = x.Hr, Minute = x.Min, Count = y.Count()});

输出

  

00:00 = 0
  00:01 = 6
  00:02 = 6
  00:03 = 7
  00:04 = 7
  00:05 = 7
  00:06 = 0
  00:07 = 0
  // ..剪断..//

实例:http://rextester.com/VOVJCS56741

答案 2 :(得分:0)

这应该没有任何join。假设只有单个日期。

var date = items.Select(i => i.date).Min();

Enumerable.Range(0, 60 * 24)
.Select(i => 
    new 
    {
        Minute = i % 60, 
        Hour = i / 60, 
        Day = date,
        Count = items.Where(j => j.date.Hour = i / 60 && j.date.Minute = i % 60).Count()
    });