4

我有一个 LARGE 数据表(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 知识不是很好,但我认为我能够做到这一点!

注意:数据表已经在机器上用于无法更改的计算/视图,所以说“别再傻了,用 SQL 过滤!!!” 是一个有效的答案,对我没用!:-D

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

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

4

4 回答 4

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 构造函数的信息,以按不同的时间部分进行分组。

于 2012-04-03T20:55:48.290 回答
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), 
            };
于 2012-04-03T20:32:28.627 回答
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"))
              };  
于 2012-04-03T20:38:18.407 回答
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])
                 });
于 2012-04-03T20:38:41.837 回答