How can you do in RX a simple, stateful transform of a sequence?
Say we want to make an exponential moving average transform of a IObservable noisySequence.
Thanks! Here is a solution using Scan
const double lambda = 0.99;
IObservable<double> emaSequence = noisySequence.Scan(Double.NaN, (emaValue, value) =>
{
if (Double.IsNaN(emaValue))
{
emaValue = value;
}
else
{
emaValue = emaValue*lambda + value*(1-lambda);
}
return emaValue;
}).Select(emaValue => emaValue);
This is how you can attach state to a sequence. In this case it calculates the average of the last 10 values.
var movingAvg = noisySequence.Scan(new List<double>(),
(buffer, value)=>
{
buffer.Add(value);
if(buffer.Count>MaxSize)
{
buffer.RemoveAt(0);
}
return buffer;
}).Select(buffer=>buffer.Average());
But you could use Window (which Buffer is sort of a generalisation of) to get your average too.
noisySequence.Window(10)
.Select(window=>window.Average())
.SelectMany(averageSequence=>averageSequence);
For many of these types of calculations, Buffer
is the easiest way
var movingAverage = noisySequence.Buffer(/*last*/ 3,
/*move forward*/ 1 /*at a time*/)
.Select(x => (x[0] + x[1] + x[2]) / 3.0);
If you need to carry state around, use the Scan
operator, which is like Aggregate
except that it yields values every iteration.
Edit: fixed comment syntax