在linq中按时间分组(仅限小时)

时间:2013-04-16 06:57:42

标签: c# linq time datatable

我有一个数据表,其中包含以下列

CallTime   CallType

15:45:00    Voice
15:30:54    Voice
00:12:14    SMS
01:13:47    Voice
05:48:23    SMS
12:00:47    Voice

现在我想要使用像这样的Linq结果

Hrs   Count
00    1
01    1
05    1
12    1
15    2

我使用Linq尝试了Group,但没有做对。

我使用了以下代码

   var groupQuery = from table in Foundrows.AsEnumerable()
                         group table by table["Call Time"] into groupedTable
                         select new
                         {
                             CallTime = groupedTable.Key,
                             CallCount = groupedTable.Count()
                         };

2 个答案:

答案 0 :(得分:3)

var groupQuery = from r in Foundrows.AsEnumerable()
                 group r by r.Field<TimeSpan>("CallTime").Hours into g
                 select new {
                    Hrs = g.Key,
                    CallCount = g.Count()
                 };

如果您的string类型列只是将其值解析为TimeSpan

var groupQuery = from r in Foundrows.AsEnumerable()
                 let time = TimeSpan.Parse(r.Field<string>("CallTime"))
                 group r by time.Hours into g
                 select new {
                    Hrs = g.Key,
                    CallCount = g.Count()
                 };

Foundrows.AsEnumerable()
         .Select(r => {
             TimeSpan time;
             return new {
                Row = r,
                Time = TimeSpan.TryParse(r.Field<string>("CallTime"), out time) ?
                       time : (TimeSpan?)null
             };
         })
         .Where(x => x.Time.HasValue)
         .GroupBy(x => x.Time.Value.Hours)
         .Select(g => new {
             Hrs = g.Key,
             CallCount = g.Count()
         });

或者您可以使用TryParse,这样会返回可为空的TimeSpan方法:

public static TimeSpan? TryParse(string s)
{
    TimeSpan time;
    if (TimeSpan.TryParse(s, out time))
       return time;

    return null;
}

并在原始查询中使用它:

var groupQuery = from r in Foundrows.AsEnumerable()
                 let time = TryParse(r.Field<string>("CallTime"))
                 where time.HasValue
                 group r by time.Value.Hours into g
                 select new {
                    Hrs = g.Key,
                    CallCount = g.Count()
                 };

答案 1 :(得分:2)

如果您想按小时分组,而“通话时间”字段是DateTime字段:

var groupQuery = from row in Foundrows.AsEnumerable()
                 let hour = row.Field<DateTime>("Call Time").Hour 
                 group row by hour into hourGroup
                 select new {
                    CallHour = hourGroup.Key,
                    CallCount = hourGroup.Count()
                 }; 

如果您想按Date + Hour

的组合进行分组
var groupQuery = from row in Foundrows.AsEnumerable()
                 let date = row.Field<DateTime>("Call Time")
                 let hour = date.Hour
                 group row by new{ date, hour } into dateHourGroup
                 select new {
                     CallDate = dateHourGroup.Key.date,
                     CallHour = dateHourGroup.Key.hour,
                     CallCount = dateHourGroup.Count()
                 }; 

编辑:如果它实际上是TimeSpan(看起来像是),请使用lazyberezovsky的方法:)

  

您的comment:如果我想使用TryParse代替Parse,那么   我需要在代码中进行更改吗?

我建议您创建一个允许返回Nullable<TimeSpan>的扩展程序,然后您可以检查是否HasValue==true

public static TimeSpan? TryGetTimeSpan(this string tsString, string format = null)
{
    TimeSpan ts;
    bool success;
    if (format == null)
        success = TimeSpan.TryParse(tsString, out ts);
    else
        success = TimeSpan.TryParseExact(tsString, format, null, TimeSpanStyles.None, out ts);
    return success ? (TimeSpan?)ts : (TimeSpan?)null;
} 

现在此查询有效运行,并且不使用未记录的副作用(作为查询中用于TimeSpan的本地TimeSpan.TryParse变量):

var groupQuery = from r in Foundrows.AsEnumerable()
                 let time = r.Field<string>("CallTime").TryGetTimeSpan()
                 where time.HasValue
                 group r by time.Value.Hours into g
                 select new
                 {
                     Hrs = g.Key,
                     CallCount = g.Count()
                 };