我有一个列表,其中每个对象都有两个字段:
我有一些这样的值:
...等等。
我需要生成另一个相同格式的列表,但要按日期累积“估计”字段。因此结果必须是:
现在,我正在foreach语句中对其进行计算
for (int iI = 0; iI < SData.TotalDays; iI++)
{
DateTime oCurrent = SData.ProjectStart.AddDays(iI);
oRet.Add(new GraphData(oCurrent, GetProperEstimation(oCurrent)));
}
然后,我可以对当前日期之前或等于当前日期的所有日期执行Linq Sum:
private static double GetProperEstimation(DateTime pDate)
{
return Data.Where(x => x.Date.Date <= pDate.Date).Sum(x => x.Estimated);
}
有效。但是问题在于ABSLOUTELLY速度很慢,一个271个元素的列表花费了超过1分钟的时间。
有更好的方法吗?
谢谢。
答案 0 :(得分:2)
这完全是MoreLinq.Scan
的工作var newModels = list.Scan((x, y) => new MyModel(y.Date, x.Estimated + y.Estimated));
新模型将具有您想要的值。
在(x, y)
中,x
是上一个项目,y
是枚举中的当前项目。
为什么查询速度慢?
因为Where
会在每次调用集合时从头开始进行迭代。因此操作数量成倍增长1 + 2 + 3 + ... + n = ((n^2)/2 + n/2)
。
答案 1 :(得分:2)
您可以编写一个简单的类似LINQ的扩展方法来累加值。该版本被概括为允许不同的输入和输出类型:
static class ExtensionMethods
{
public static IEnumerable<TOut> Accumulate<TIn, TOut>(this IEnumerable<TIn> source, Func<TIn,double> getFunction, Func<TIn,double,TOut> createFunction)
{
double accumulator = 0;
foreach (var item in source)
{
accumulator += getFunction(item);
yield return createFunction(item, accumulator);
}
}
}
用法示例:
public static void Main()
{
var list = new List<Foo>
{
new Foo { Date = new DateTime(2018,1,1), Estimated = 1 },
new Foo { Date = new DateTime(2018,1,2), Estimated = 2 },
new Foo { Date = new DateTime(2018,1,3), Estimated = 3 },
new Foo { Date = new DateTime(2018,1,4), Estimated = 4 },
new Foo { Date = new DateTime(2018,1,5), Estimated = 5 }
};
var accumulatedList = list.Accumulate
(
(item) => item.Estimated, //Given an item, get the value to be summed
(item, sum) => new { Item = item, Sum = sum } //Given an item and the sum, create an output element
);
foreach (var item in accumulatedList)
{
Console.WriteLine("{0:yyyy-MM-dd} {1}", item.Item.Date, item.Sum);
}
}
输出:
2018-01-01 1
2018-01-02 3
2018-01-03 6
2018-01-04 10
2018-01-05 15
这种方法只需要对集合进行一次迭代,因此其性能要比一系列求和更好。
答案 2 :(得分:1)
您可以尝试一下。简单而有效。
var i = 0;
var result = myList.Select(x => new MyObject
{
Date = x.Date,
Estimated = i = i + x.Estimated
}).ToList();
编辑:以这种方式尝试
.Select(x => new GraphData(x.Date, i = i + x.Estimated))
答案 3 :(得分:1)
我会假设您所说的是真实的,您需要的是什么
算法
Create a list or array of values based in the original values ordered date asc
sumValues=0;
foreach (var x in collection){
sumValues+= x.Estimated; //this will accumulate all the past values and present value
oRet.Add(x.date, sumValues);
}
第一步(对值进行排序)是最重要的。对于每个将非常快。 参见sort