【问题标题】:Aggregate value takes very long time总价值需要很长时间
【发布时间】:2014-03-30 11:30:52
【问题描述】:

我有一个全年 15 分钟值的大列表。我想把它们聚合成几个小时。我正在以非常简单的方式做到这一点:

for (; from <= to; from = from.AddHours(1))
{
    List<DataPoint> valuesToAgregate = data.Where(x => x.TimeStamp >= from && x.TimeStamp < from.AddHours(1)).ToList();
    dailyInputData.Add(valuesToAgregate.Sum(x=>x.Val));

}

这种方式需要很多时间,比如 35k 的值需要 30 秒,有什么办法可以优化吗?也许使用排序功能或一些如何将索引添加到列表或使用分组而不是 for 循环?

【问题讨论】:

  • 你真的需要临时的List&lt;DataPoint&gt; 实例吗?
  • 它有很大的不同吗?这是简化逻辑,我将此列表传递给其他方法。但问题是 data.Where(x => x.TimeStamp >= from && x.TimeStamp
  • @kosnkov 这很重要,您在每个循环中都创建了一个数组。不仅你循环序列两次(一个是ToList另一个是Sum
  • 可能会进行进一步优化,但我会开始尝试省略该临时列表。是的,它可以有所作为;当您不需要任何列表时,您正在分配 List&lt;DataPoint&gt; 并添加 data 的子集。如果您只想将选择命令分成几行,请将 valuesToAgregate 声明为 IEnumerable&lt;DataPoint&gt; 并省略 ToList() 调用 - 您将获得相同的简化(在可读性方面),但不会保存子集介于两者之间;它将被懒惰地评估。
  • 您可以优化的另一个细节是,目前,您为每个项目调用 from.AddHours(1)(在传递给 Where 的 lambda 表达式中,而不是将结果存储在变量中,然后在 lambda表达式。编译器可能不会自行优化它,因为它不知道对from.AddHours(1) 的每次调用是否为给定的from 返回相同的值。

标签: c#


【解决方案1】:

当然,如果您之前通过 TimeStamp 订购您的清单,这会更快。示例:

var orderedData = data.OrderBy(item => item.TimeStamp).ToList();
int firstIndex = 0;
var from = orderedData.First().TimeStamp;
var to = orderedData.Last().TimeStamp;
while (from < to)
{
    var sum = 0;
    var newTo = from.AddHours(1);
    while (firstIndex < data.Count && orderedData[firstIndex].TimeStamp < newTo)
    {
        sum += orderedData[firstIndex].Val;
        ++firstIndex;
    }
    dailyInputData.Add(sum);
    from = from.AddHours(1);
 }

【讨论】:

  • 不使用.Count()方法你可以只使用List&lt;T&gt;Count属性,当然如果数据类型是List&lt;T&gt;IList&lt;T&gt;时可以使用这个方法
  • @Selman22,是的,你是对的,thanx。如果data 不是IList&lt;T&gt;,我们可以使用orderedData 并得到它的Count
【解决方案2】:
data = data.Sort(x=>x.TimeStamp);
int counter = 0;
var boundary = from.AddHours(1);
foreach(var d in data){
    if(d.TimeStamp > boundary){
        boundary = boundary.AddHours(1);
        counter = 0;
        dailyInputData.Add(counter);
    }
    ++counter;
}

这个问题出在逻辑上

  1. 每次都会从头到尾扫描列表以找到候选值(您的 where 子句)
  2. 候选值被插入到另一个临时列表中
  3. 然后从头到尾扫描临时列表以计算总和

最快的方法:

  1. 对列表进行排序
  2. 遍历项目,如果它们属于当前组,则添加计数器,否则您已跳转到新组,刷新计数器以记录值并重新开始

【讨论】:

    猜你喜欢
    • 2013-09-07
    • 2020-08-26
    • 2014-10-09
    • 2012-11-26
    • 2019-12-27
    • 2017-10-22
    • 2020-11-15
    • 2016-05-19
    • 2011-11-20
    相关资源
    最近更新 更多