LINQ计算SortedList的移动平均值< dateTime,double>
我有一个时间序列,形式为
SortedList<dateTime,double>
。我想计算一下这个系列的移动平均线。我可以使用简单的for循环来做到这一点。我想知道是否有更好的方法来使用linq。
我的版本:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var mySeries = new SortedList<DateTime, double>();
mySeries.Add(new DateTime(2011, 01, 1), 10);
mySeries.Add(new DateTime(2011, 01, 2), 25);
mySeries.Add(new DateTime(2011, 01, 3), 30);
mySeries.Add(new DateTime(2011, 01, 4), 45);
mySeries.Add(new DateTime(2011, 01, 5), 50);
mySeries.Add(new DateTime(2011, 01, 6), 65);
var calcs = new calculations();
var avg = calcs.MovingAverage(mySeries, 3);
foreach (var item in avg)
{
Console.WriteLine("{0} {1}", item.Key, item.Value);
}
}
}
class calculations
{
public SortedList<DateTime, double> MovingAverage(SortedList<DateTime, double> series, int period)
{
var result = new SortedList<DateTime, double>();
for (int i = 0; i < series.Count(); i++)
{
if (i >= period - 1)
{
double total = 0;
for (int x = i; x > (i - period); x--)
total += series.Values[x];
double average = total / period;
result.Add(series.Keys[i], average);
}
}
return result;
}
}
}
没有找到相关结果
已邀请:
7 个回复
坝胺绣敝
元素的总和,而是可以保持运行总计并在每次迭代时进行调整。也就是说,改变这个:
对此:
这意味着无论
的大小如何,您的代码都将花费相同的执行时间。
梦话快家腹
函数,如
累积值(以匿名类型实现)包含两个字段:
包含到目前为止构建的结果列表。
包含最后的
元素。聚合函数将当前值添加到工作列表,构建当前平均值并将其添加到结果中,然后从工作列表中删除第一个(即最旧的)值。 通过将第一个
元素放入
并将
初始化为空列表来构建“种子”(即累积的起始值)。 因此,聚合开始于元素
(通过在开头跳过
元素) 在函数式编程中,这是aggretate(或
)函数的典型使用模式,顺便说一句。 两个评论: 解决方案不是“功能性”清洁,因为在每个步骤中都重复使用相同的列表对象(
和
)。如果未来的某些编译器试图自动并行化Aggregate函数,我不确定这是否会引起问题(另一方面,我也不确定,如果可能的话......)。纯功能解决方案应该在每一步“创建”新列表。 另请注意,C#缺少强大的列表表达式。在一些假设的Python-C#混合伪代码中,可以编写聚合函数
在我的拙见:)这会更优雅:)
剑哎
此类提供了一个非常快速且轻量级的MovingAverage过滤器实现。它创建一个长度为N的循环缓冲区,并计算每附加一个数据点的一个加法,一个减法和一个乘法,而不是强力实现的每个点的N乘加。 接下来,到LINQ-ify吧!
上述扩展方法包装MovingAverage类并允许插入IEnumerable流。 现在用它!
惜堡沁戚
可以改写为:
您的方法可能如下所示:
如你所见,linq非常富有表现力。我建议从一些教程开始,比如介绍LINQ和101 LINQ Samples。
仇聘发栖
方法,该方法存在于Rx中但不存在于LINQ中。 让我们来看看如果我们有扫描方法会是什么样子
这是扫描方法,从这里采取和调整:
这应该比蛮力方法具有更好的性能,因为我们使用运行总计来计算SMA。 这里发生了什么? 首先,我们需要计算我们称之为
的第一个时期。然后,我们从累积的种子值计算每个后续值。要做到这一点,我们需要旧的值(即t-delta)和我们将系列压缩在一起的最新值,一次从开始,一次移动三角洲。 最后,我们通过在第一个周期的长度上添加零并添加初始种子值来进行一些清理。
恋卡
方法,这显着简化了代码:
骇毖煽洁铂