C# 列表迭代性能
我有一个for循环,它总共进行24次迭代,每次迭代代表一天中的一个小时,然后在另一个嵌套的for循环中每隔15分钟检查一次。另一个嵌套检查列表中的小时和分钟值,然后聚合列表中的某些项目(如果它们满足我的时间要求)。问题是我的列表最多可以包含100万条记录,这意味着我可以24*4次遍历100万条记录 在这种情况下,如何优化代码以提高性能?我知道这可能可以用LINQ语句简化,但我不确定它是否会更快。下面是我正在做的一个例子C# 列表迭代性能,c#,.net,performance,C#,.net,Performance,我有一个for循环,它总共进行24次迭代,每次迭代代表一天中的一个小时,然后在另一个嵌套的for循环中每隔15分钟检查一次。另一个嵌套检查列表中的小时和分钟值,然后聚合列表中的某些项目(如果它们满足我的时间要求)。问题是我的列表最多可以包含100万条记录,这意味着我可以24*4次遍历100万条记录 在这种情况下,如何优化代码以提高性能?我知道这可能可以用LINQ语句简化,但我不确定它是否会更快。下面是我正在做的一个例子 List<SummaryData> Aggregates = n
List<SummaryData> Aggregates = new List<SummaryData>();
for(int startHour = 0; startHour < 24; startHour++)
{
for(int startMin = 0; startMin < 60; startMin+= 15)
{
int aggregateData = 0;
//My ItemList can have up to 1 million records.
foreach(ListItem item in ItemList)
{
if((item.time.Hour == startHour)&&(item.time.Minute == startMinute))
{
aggregateData += item.number;
}
}
SummaryData aggregate = new SummaryData { SummaryId = item.id, TotalNumber = aggregateData
Aggregates.Add(aggregate);
}
}
class SummaryData
{
public int SummaryId {get; set;}
public int TotalNumber {get; set;}
}
不要在每一项中查找每一小时和每一分钟,只需在ItemList上迭代一次,然后根据每个item.time.Hour和item.time.Minute采取行动。不要在每一项中查找每一小时和每一分钟,只需在ItemList上迭代一次,并根据每个item.time.Hour和item.time.Minute采取行动。我将大致如下组织数据: 另见:
我大概会这样组织数据: 另见:
根据上面的逻辑,您应该只需要迭代列表一次。您可以将for循环嵌套在foreach中,并可能获得更好的性能。我还将使用字典保存聚合数据,并将其键基于总分钟数,即小时*60+分钟
根据上面的逻辑,您应该只需要迭代列表一次。您可以将for循环嵌套在foreach中,并可能获得更好的性能。我还将使用字典保存聚合数据,并将其键基于总分钟数,即小时*60+分钟
这个算法的结果是什么?如果我没有得到它,我会道歉 它似乎标识itemList中分钟值可被15整除的所有项目,然后将其数值添加到运行计数器中,然后将运行计数器添加到该聚合对象中 因为我不清楚这些物体的类型,我对这里实际发生的事情有点模糊。您似乎使用aggregateData+=item.number聚合了一次,然后使用Aggregates.AddaggregateData再次聚合。您确定没有对这些内容进行双重求和吗?我甚至不清楚您是在尝试对限定项的值求和,还是创建它们的列表 除此之外,24*4次浏览100万个项目的整个列表肯定不是必需的,也不是最佳的,但如果没有对目标的更清晰理解,我无法确定什么是正确的
正如其他答案中所建议的,正确的方法可能会在itemList上迭代一次并对每个项目进行操作,而不是迭代100次并丢弃列表中的每个项目99次,因为您知道它只能满足100次迭代中的一次。此算法的结果是什么?如果我没有得到它,我会道歉 它似乎标识itemList中分钟值可被15整除的所有项目,然后将其数值添加到运行计数器中,然后将运行计数器添加到该聚合对象中 因为我不清楚这些物体的类型,我对这里实际发生的事情有点模糊。您似乎使用aggregateData+=item.number聚合了一次,然后使用Aggregates.AddaggregateData再次聚合。您确定没有对这些内容进行双重求和吗?我甚至不清楚您是在尝试对限定项的值求和,还是创建它们的列表 除此之外,24*4次浏览100万个项目的整个列表肯定不是必需的,也不是最佳的,但如果没有对目标的更清晰理解,我无法确定什么是正确的
正如其他答案中所建议的,正确的方法可能是在itemList上迭代一次并对每个项目进行操作,而不是迭代100次并丢弃列表中的每个项目99次,因为您知道它只能满足100次迭代中的一次。您的问题陈述有点模糊。看起来您需要一个按项目id列出的摘要,提供时间戳位于整数四分之一小时边界上的所有项目编号的总和 我认为下面的方法应该可以奏效 一次通过列表 数据存储是一个高度平衡的二叉树,因此查找、插入和删除都是Olog N。 代码如下:
public class SummaryData
{
public SummaryData( int id )
{
this.SummaryId = id ;
this.TotalNumber = 0 ;
}
public int SummaryId { get; set; }
public int TotalNumber { get; set; }
}
public class ListItem
{
public int Id ;
public int Number ;
public DateTime Time ;
}
public IEnumerable<SummaryData> Summarize( IEnumerable<ListItem> ItemList )
{
const long TICKS_PER_QUARTER_HOUR = TimeSpan.TicksPerMinute * 15;
SortedDictionary<int,SummaryData> summary = new SortedDictionary<int , SummaryData>();
foreach ( ListItem item in ItemList )
{
long TimeOfDayTicks = item.Time.TimeOfDay.Ticks;
bool on15MinuteBoundary = ( 0 == TimeOfDayTicks % TICKS_PER_QUARTER_HOUR ? true : false );
if ( on15MinuteBoundary )
{
int key = (int)( TimeOfDayTicks / TICKS_PER_QUARTER_HOUR );
SummaryData value;
bool hasValue = summary.TryGetValue( key , out value );
if ( !hasValue )
{
value = new SummaryData( item.Id );
summary.Add( value.SummaryId , value ) ;
}
value.TotalNumber += item.Number;
}
}
return summary.Values;
}
你的问题陈述有点模糊。看起来您需要一个按项目id列出的摘要,提供时间戳位于整数四分之一小时边界上的所有项目编号的总和 我认为下面的方法应该可以奏效 一次通过列表 数据存储是一个高度平衡的二叉树,因此查找、插入和删除都是Olog N。 代码如下:
public class SummaryData
{
public SummaryData( int id )
{
this.SummaryId = id ;
this.TotalNumber = 0 ;
}
public int SummaryId { get; set; }
public int TotalNumber { get; set; }
}
public class ListItem
{
public int Id ;
public int Number ;
public DateTime Time ;
}
public IEnumerable<SummaryData> Summarize( IEnumerable<ListItem> ItemList )
{
const long TICKS_PER_QUARTER_HOUR = TimeSpan.TicksPerMinute * 15;
SortedDictionary<int,SummaryData> summary = new SortedDictionary<int , SummaryData>();
foreach ( ListItem item in ItemList )
{
long TimeOfDayTicks = item.Time.TimeOfDay.Ticks;
bool on15MinuteBoundary = ( 0 == TimeOfDayTicks % TICKS_PER_QUARTER_HOUR ? true : false );
if ( on15MinuteBoundary )
{
int key = (int)( TimeOfDayTicks / TICKS_PER_QUARTER_HOUR );
SummaryData value;
bool hasValue = summary.TryGetValue( key , out value );
if ( !hasValue )
{
value = new SummaryData( item.Id );
summary.Add( value.SummaryId , value ) ;
}
value.TotalNumber += item.Number;
}
}
return summary.Values;
}
使用lamda表达式进行比较。只需使用Linq GroupBy和Sum扩展名:Consid
呃,改变你们的结构,比如改变一个排序列表或者散列图。我不能理解外循环的含义。它不是涵盖了小时内所有可能的值吗?我不完全确定您是否在尝试完成我有点累,因此如果不了解这一点,似乎应该可以将外部循环移动到内部循环中,例如,对每个列表项运行24*4测试,不是对整个列表进行24*4测试。使用lamda表达式进行比较。只需使用Linq GroupBy和Sum扩展:考虑更改您的结构,例如更改为排序列表或哈希映射。我无法理解外循环的含义。它不是涵盖了小时内所有可能的值吗?我不完全确定您是否在尝试完成我有点累,因此如果不了解这一点,似乎应该可以将外部循环移动到内部循环中,例如,对每个列表项运行24*4测试,不是对整个列表进行24*4测试。我认为更有效的方法是在分组后使用总和扩展。我确实认为像您建议的那样使用int键可能会更简单,但是在Linq中很容易更改approach@sehe:LINQ解决方案可能更具可读性,但由于OP寻求优化,这应该更快,LINQ将在分组时引入中间存储对象。我认为更有效的方法是在分组后使用总和扩展。我确实认为像您建议的那样使用int键可能会更简单,但是在Linq中很容易更改approach@sehe:LINQ解决方案可能更具可读性,但由于OP正在寻求优化,因此这应该更快。在分组时,LINQ将引入中间存储对象。Mmm。发现您希望将每15分钟分组后更新答案。。。抱歉读得太草率了。发现您希望将每15分钟分组后更新答案。。。抱歉读得太草率了
public class SummaryData
{
public SummaryData( int id )
{
this.SummaryId = id ;
this.TotalNumber = 0 ;
}
public int SummaryId { get; set; }
public int TotalNumber { get; set; }
}
public class ListItem
{
public int Id ;
public int Number ;
public DateTime Time ;
}
public IEnumerable<SummaryData> Summarize( IEnumerable<ListItem> ItemList )
{
const long TICKS_PER_QUARTER_HOUR = TimeSpan.TicksPerMinute * 15;
SortedDictionary<int,SummaryData> summary = new SortedDictionary<int , SummaryData>();
foreach ( ListItem item in ItemList )
{
long TimeOfDayTicks = item.Time.TimeOfDay.Ticks;
bool on15MinuteBoundary = ( 0 == TimeOfDayTicks % TICKS_PER_QUARTER_HOUR ? true : false );
if ( on15MinuteBoundary )
{
int key = (int)( TimeOfDayTicks / TICKS_PER_QUARTER_HOUR );
SummaryData value;
bool hasValue = summary.TryGetValue( key , out value );
if ( !hasValue )
{
value = new SummaryData( item.Id );
summary.Add( value.SummaryId , value ) ;
}
value.TotalNumber += item.Number;
}
}
return summary.Values;
}