RX: Stateful transform of sequence, e.g. exponential moving average

后端 未结 3 2018
日久生厌
日久生厌 2021-01-05 10:52

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.

相关标签:
3条回答
  • 2021-01-05 11:29

    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);
    
    0 讨论(0)
  • 2021-01-05 11:30

    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);
    
    0 讨论(0)
  • 2021-01-05 11:31

    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

    0 讨论(0)
提交回复
热议问题