c# - 取消嵌套列表迭代以提高性能

标签 c# performance linq

为了执行计算,我需要遍历多个列表。总之,List1 是道路起点和终点 (ids) 的列表,List2 是这些终点的单个速度样本的列表(每组终点都有多个速度样本)。 List1 定义如下:

class RoadwaySegment
{ 
   public int StartId {get; set;} 
   public int EndId {get; set;}
}

List2 定义如下:

class IndividualSpeeds
{ 
   public int StartHour {get; set;} 
   public int StartMin {get; set;} //either 0,15,30,or 45
   public int Speed {get; set;} 
   public int StartId {get; set;} 
   public int EndId {get; set;}
}

List3 是我的计算结果,将包含 List1 中道路路段在一天中每 15 分钟的平均速度。 List3 看起来像这样:

class SummaryData
{ 
  public string SummaryHour {get; set;} 
  public string SummaryMin {get; set;} 
  public int StartId {get; set;} 
  public int EndId {get; set;} 
  public int AvgSpeed {get; set;}
}

目前,为了生成 List3,我对 List1 进行迭代,然后在一天中的每 24 小时内迭代,然后在每小时的每 15 分钟间隔内迭代。对于这些迭代中的每一个,我检查 List2 中的单个速度样本是否应该包含在我的道路段的平均速度计算中。所以,它看起来像这样:

var summaryList = new List<SummaryData>();
foreach (var segment in RoadwaySegments)
{
   for(int startHour = 0; startHour < 24; startHour++)
   {
      for(int startMin = 0; startMin < 60; startMin+= 15)
      {
         int totalSpeeds = 0;
         int numSamples = 0;
         int avgSpeed = 0;

         foreach(var speedSample in IndividualSpeeds)
         {
            if((segment.StartId == speedSample.StartId)&&(segment.EndId == speedSample.EndId)&&(speedSample.StartHour == startHour)&&(speedSample.StartMin == startMin))
            {
               if(speedSample.Speed > 0)
               {
                  totalSpeeds += speedSample.Speed;
                  numSamples += 1;
               }
            }
         }
         SummaryData summaryItem = new SummaryData {SummaryHour = startHour, SummaryMin = startMin, StartId = segment.StartId, EndId = segment.EndId, AvgSpeed = totalSpeeds/numSamples;
         summaryList.Add(summaryItem);
      }
   }
}

此代码的问题在于,List1 可能有一百个路段,但 List2 可能包含一百万或更多速度样本记录,因此列表的子迭代非常耗时。有没有办法使用 GroupBy/LINQ 来提高这段代码的性能和可读性?请注意在平均值中包括速度的条件——它必须大于 0。

最佳答案

这是未经测试的,但我认为它会起作用:

from segment in RoadwaySegments
join sample in IndividualSpeeds on new { segment.StartId, segment.EndId } equals new { sample.StartId, sample.EndId } into segmentSamples
from startHour in Enumerable.Range(0, 24)
from startMin in new[] { 0, 15, 30, 45 }
let startMinSamples = segmentSamples
    .Where(sample => sample.Speed > 0)
    .Where(sample => sample.StartHour == startHour)
    .Where(sample => sample.StartMin == startMin)
    .Select(sample => sample.Speed)
    .ToList()
select new SummaryItem
{
    StartId = segment.StartId,
    EndId = segment.EndId,
    SummaryHour = startHour,
    SummaryMin = minute,
    AvgSpeed = startMinSamples.Count <= 2 ? 0 : startMinSamples.Average()
};

主要思想是迭代片段和样本列表一次,为每个片段生成一组样本。然后,对于这些组中的每一个,您为每个组合生成小时和分钟以及摘要项。最后,您计算小时/分钟组合中所有非零样本的平均速度。

这不是很理想,因为您仍然将片段的样本迭代 24 * 4 次,但它比迭代整个样本列表要好得多。这应该会让您走上正确的道路,希望您可以进一步优化最后一点。

关于c# - 取消嵌套列表迭代以提高性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7573884/

相关文章:

python - 为什么 numpy 函数在 pandas 系列/数据帧上这么慢?

c++ - 天真的把 C++ 翻译成 Julia,有优化的空间吗?

c# - 使用 DataTable 和 Linq 导出到 Excel 时缺少某些数据

c# - 使用 Lambda 表达式创建自定义列表

c# - WPF:如何使路径的大小符合其父级的大小

c# - EF4 中的并发性 - 如何有条件地创建实体

c# - 我们可以使用枚举作为类型安全的实体 ID 吗?

c# - TornLifestyle 简易注入(inject)器

java - 大多数编程语言的时间复杂度?

c# - 转换为值类型 'Int32' 失败,因为具体化值为 null