按DateTime分组数据表中的DateTime行 - C#

时间:2012-04-03 20:25:37

标签: c# linq datetime datatable group-by

我有一个大的数据表(500k-1m行),没有详细说明这是一个要求,因为最终用户需要/希望能够看到所有数据。这是在本地服务器上,所以带宽等对我来说不是问题。

我在DataTable中有一个DateTime字段,我需要对其进行分组,让我通过分组来解释我的意思......这可能不是你的意思(从这里查看其他问题!)。

        var table = new DataTable();
        table.Columns.Add("EventTime", typeof(DateTime));
        table.Columns.Add("Result", typeof(String));
        table.Columns.Add("ValueOne", typeof(Int32));
        table.Columns.Add("ValueTwo", typeof(Int32));
        table.Rows.Add("2012-02-06 12:41:45.190", "A", "7", "0");
        table.Rows.Add("2012-02-06 12:45:41.190", "B", "3", "89");
        table.Rows.Add("2012-02-06 12:59:41.190", "C", "1", "0");
        table.Rows.Add("2012-02-06 13:41:41.190", "D", "0", "28");
        table.Rows.Add("2012-02-06 17:41:41.190", "E", "0", "37");
        table.Rows.Add("2012-02-07 12:41:45.190", "F", "48", "23");

我希望将上表分组,以便得到“ValueOne”列的总和,以及“ValueTwo”列的平均值。我需要分组有点灵活,以便我可以指定我想要按分钟分组(只有第一行和最后一行会被分组,其余行只提供它们的值),或者按天(除了最后一行之外的所有行)将分组为单行)等。

我已经尝试了几次,但我没有在哪里。我的LINQ知识不是很好,但我想我能做到这一点!

注意:DataTable已经在机器上用于无法更改的计算/视图,因此说“停止成为白痴,在SQL中过滤!!!”是一个有效的答案,对我来说没用! :-D

另外,如果你在标题中错过了它,我需要在C#中使用它 - 我正在使用.NET 4.0 ...

提前致谢,假设您决定提供帮助! : - )

4 个答案:

答案 0 :(得分:5)

其他三个答案很接近,但正如你所指出的那样,它们分组在同一秒内发生的事件,而不是在同一秒内发生的事件,这就是你想要的。试试这个:

var query = from r in table.Rows.Cast<DataRow>()
        let eventTime = (DateTime)r[0]
        group r by new DateTime(eventTime.Year, eventTime.Month, eventTime.Day, eventTime.Hour, eventTime.Minute, eventTime.Second)
            into g
        select new {
                g.Key,
                Sum = g.Sum(r => (int)r[2]),
                Average = g.Average(r => (int)r[3])
            };

您可以调整传递给DateTime构造函数的信息,以便按不同的时间部分进行分组。

答案 1 :(得分:1)

您需要更改的唯一内容是您要分组的属性。

var query = from x in DataSource
            group x by x.EventTime.Minute into x
            select new
            {
              Unit = x.Key,
              SumValueOne = x.Sum(y => y.ValueOne),
              AverageValueTwo = x.Average(y => y.ValueTwo), 
            };

答案 2 :(得分:1)

这样的事情应该有效:

DataTable dt = GetDataTableResults();

var results = from row in dt.AsEnumerable()
              group row by new { EventDate = row.Field<DateTime>("EventTime").Date } into rowgroup
              select new
              {
                  EventDate = rowgroup.Key.EventDate,
                  ValueOne = rowgroup.Sum(r => r.Field<int>("ValueOne")),
                  ValueTwo = rowgroup.Average(r => r.Field<decimal>("ValueTwo"))
              };  

答案 3 :(得分:0)

以下是基线代码的样子:

var query = table.Rows.Cast<DataRow>()
    .GroupBy(r => ((DateTime)r[0]).Second)
    .Select(g => new
                 {
                    g.Key, 
                    Sum = g.Sum(r => (int)r[2]),
                    Average = g.Average(r => (int)r[3])
                 });

为了增加灵活性,你可以这样:

IEnumerable<IGrouping<object, DataRow>> Group(IEnumerable<DataRow> rows, GroupType groupType)
{
    // switch case would be preferable, but you get the idea.
    if(groupType == GroupType.Minutes) return rows.GroupBy(r => ((object)((DateTime)r[0]).Minute));
    if(groupType == GroupType.Seconds) return rows.GroupBy(r => ((object)((DateTime)r[0]).Second));
    ...
}

var baseQuery = table.Rows.Cast<DataRow>();
var grouped = Group(baseQuery, groupType);
var query = grouped
    .Select(g => new
                 {
                    g.Key, 
                    Sum = g.Sum(r => (int)r[2]),
                    Average = g.Average(r => (int)r[3])
                 });