我有一个for循环,它执行24次迭代,每次迭代代表一天中的一个小时,然后在另一个嵌套for循环中检查每个15分钟的间隔。另一个嵌套检查List的小时和分钟值,然后在满足我的时间要求时聚合我的List中的一些项目。问题是我的列表可以包含多达100万条记录,这意味着我可以24 * 4次遍历100万条记录。
在这种情况下,如何优化代码以提高性能?我知道这可能会用LINQ语句简化,但我不确定它会让它更快。这是我正在做的一个例子。
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;}
}
答案 0 :(得分:4)
不是在每个Hour
中查找每个Minute
和item
,而是只对ItemList
进行一次迭代,并根据每个item.time.Hour
和{{进行操作1}}。
答案 1 :(得分:4)
鉴于您的逻辑,您应该只需要迭代列表一次。您可以将for
循环嵌套在foreach
中,并可能获得更好的效果。我还会使用Dictionary
来保存您的汇总数据,并将其密钥基于总分钟数(意为hour * 60 + minute
)。
Dictionary<int, AggregateDate> aggregate = new Dictionary<int, AggregateData>();
foreach(ListItem item in ItemList)
{
int key = item.Hour * 60 + item.Minute;
AggregateData data;
if(!aggregate.TryGetValue(key, out data))
{
aggregate.Add(key, data = new AggregateData());
}
data.Number += item.Number;
}
答案 2 :(得分:1)
我将大致像这样组织数据:
using System;
using System.Linq;
using System.Collections.Generic;
public class P
{
struct DataItem
{
public System.DateTime time;
public int number;
}
public static void Main(string[] args)
{
var ItemList = new DataItem[] {} ;
var groups = ItemList
.GroupBy(item => item.time.Hour * 60 + (item.time.Minute/15)*15 );
var sums = groups
.ToDictionary(g => g.Key, g => g.Sum(item => item.number));
// lookups now become trivially easy:
int slot1900 = sums[1900];
int slot1915 = sums[1915];
int slot1930 = sums[1930];
}
}
答案 3 :(得分:0)
此算法的结果是什么?抱歉,如果我因为没有得到它而感到愚蠢。
它似乎识别itemList中的所有项目,其分钟值可以被15整除,然后将其数值添加到正在运行的计数器中,然后将该运行计数器添加到此Aggregates对象中。
因为我不清楚其中某些物体的类型,所以我对这里发生的事情有点模糊。您似乎使用“aggregateData + = item.number”聚合一次,然后使用“Aggregates.Add(aggregateData)”聚合AGAIN,您确定不会对这些内容进行双重求和吗?如果您正在尝试对合格项目的值进行求和或创建它们列表,我甚至都不清楚。
除此之外,绝对没有必要或最优的方式24 * 4次遍历100万件物品的整个清单,但如果没有更清楚地了解目标,我无法确定什么是正确的。
正如其他答案中所建议的那样,正确的方法很可能只对itemList进行一次迭代并对每一项进行操作,而不是迭代~100次并丢弃列表中的每个项目~99次(因为你知道它可以只有资格参加~100次迭代之一。)
答案 4 :(得分:0)
你的问题陈述有点模糊。看起来您想要一个按项目ID的摘要,为您提供所有项目编号的总和,其中时间戳位于整数的四分之一小时边界内。
我认为以下应该可以解决问题。
以下是代码:
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;
}