我有两个巨大的创建对象列表。一个包含来自不同资源的所有预测的List<Forecast>和一个具有这些资源能力的List<Capacity>。
Forecast还包含布尔值,表示该资源是否超过或低于他所有预测的总和。
public class Forecast
{
public int ResourceId { get; set; }
public double? ForecastJan { get; set; }
// and ForecastFeb, ForecastMarch, ForecastApr, ForecastMay, etc.
public bool IsOverForecastedJan { get; set; }
// and IsOverForecastedFeb, IsOverForecastedMarch, IsOverForecastedApr, etc.
}
public class Capacity
{
public int ResourceId { get; set; }
public double? CapacityJan { get; set; }
// and CapacityFeb, CapacityMar, CapacityApr, CapacityMay, etc.
}我必须设置IsOverForecastXXX属性,所以我必须知道每个月对每个资源的预测之和是否高于这个特定资源的容量之和。
这是我的代码:
foreach (Forecast f in forecastList)
{
if (capacityList.Where(c => c.Id == f.ResourceId)
.Select(c => c.CapacityJan)
.First()
< forecastList.Where(x => x.ResourceId == f.ResourceId)
.Sum(x => x.ForecastJan)
)
{
f.IsOverForecastedJan = true;
}
//Same for each month...
}我的代码可以工作,但是当列表太大(数千个元素)时,我的性能真的很差。
你能怎样改进这个算法?如何将每种资源的预测和相关容量进行比较?
发布于 2014-03-10 12:31:37
您可以使用First或FirstOrdefault获取currect资源的容量,然后比较它们。我会使用类似于ToLookup的Dictionary来获得所有资源的所有预测。
ILookup<int, Forecast> forecastMonthGroups = forecastList
.ToLookup(fc => fc.ResourceId);
foreach (Forecast f in forecastList)
{
double? janSum = forecastMonthGroups[f.ResourceId].Sum(fc => fc.ForecastJan);
double? febSum = forecastMonthGroups[f.ResourceId].Sum(fc => fc.ForecastFeb);
var capacities = capacityList.First(c => c.ResourceId == f.ResourceId);
bool overJan = capacities.CapacityJan < janSum;
bool overFeb = capacities.CapacityFeb < febSum;
// ...
f.IsOverForecastedJan = overJan;
f.IsOverForecastedFeb = overFeb;
// ...
}似乎每个ResourceID只有一个ResourceID,然后我将使用Dictionary存储从ResourceId到Capacity的“方式”,这将进一步提高性能:
ILookup<int, Forecast> forecastMonthGroups = forecastList
.ToLookup(fc => fc.ResourceId);
Dictionary<int, Capacity> capacityResources = capacityList
.ToDictionary(c => c.ResourceId);
foreach (Forecast f in forecastList)
{
double? janSum = forecastMonthGroups[f.ResourceId].Sum(fc => fc.ForecastJan);
double? febSum = forecastMonthGroups[f.ResourceId].Sum(fc => fc.ForecastFeb);
bool overJan = capacityResources[f.ResourceId].CapacityJan < janSum;
bool overFeb = capacityResources[f.ResourceId].CapacityFeb < febSum;
// ...
f.IsOverForecastedJan = overJan;
f.IsOverForecastedFeb = overFeb;
// ...
}发布于 2014-03-10 12:39:02
在进入循环之前,我会尝试选择每个月的容量和预测值,这样您就不会每次循环循环时迭代每个列表。
就像这样:
var capicities = capacityList.GroupBy(c => c.ResourceId).ToDictionary(c=>c.First().ResourceId, c=>c.First().CapacityJan);
var forecasts = forecastList.GroupBy(x => x.ResourceId).ToDictionary(x => x.First().ResourceId, x => x.Sum(f => f.ForecastJan));
foreach (Forecast f in forecastList)
{
if (capicities[f.ResourceId] < forecasts[f.ResourceId])
{
f.IsOverForecastedJan = true;
}
}发布于 2014-03-10 12:45:46
为了加快速度,你可以做很多事情。首先,对forecastList进行一次检查,并对每个月的容量预测进行求和:
var demandForecasts = new Dictionary<int, double?[]>();
foreach (var forecast in forecastList)
{
var rid = forecast.ResourceId;
if (!demandForecasts.ContainsKey(rid))
{
demandForecasts[rid] = new double?[12];
}
var demandForecast = demandForecasts[rid];
demandForecast[0] += forecast.ForecastJan;
// etc
demandForecast[11] += forecast.ForecastDec;
}对容量进行同样的操作,从而生成一个capacities字典。然后,在forecastList上再循环一次,以设置“over预测性”标志:
foreach (var forecast in forecastList)
{
var rid = forecast.ResourceId;
forecast.IsOverForecastedJan = capacities[rid][0] < demandForecast[rid][0];
// ...
forecast.IsOverForecastedDec = capacities[rid][11] < demandForecast[rid][11];
}从这段代码中隐含的12倍代码重复可以明显看出,每个月作为单独属性的建模能力等可能不是最好的方法--使用某种索引集合可以消除重复。
https://stackoverflow.com/questions/22300015
复制相似问题