.net IObservable如何<;双倍>;。平均值应该有效吗? 更新

.net IObservable如何<;双倍>;。平均值应该有效吗? 更新,.net,average,system.reactive,.net,Average,System.reactive,看起来Jon Skeet是对的(大惊喜!),问题在于我假设Average扩展提供了一个连续的平均值(它没有) 对于我所追求的行为,我编写了一个简单的ContinuousAverage扩展方法,我在这里介绍了该方法的实现,以方便其他可能需要类似方法的人: public static class ObservableExtensions { private class ContinuousAverager { private double _mean;

看起来Jon Skeet是对的(大惊喜!),问题在于我假设
Average
扩展提供了一个连续的平均值(它没有)

对于我所追求的行为,我编写了一个简单的
ContinuousAverage
扩展方法,我在这里介绍了该方法的实现,以方便其他可能需要类似方法的人:

public static class ObservableExtensions {
    private class ContinuousAverager {
            private double _mean;
            private long _count;

        public ContinuousAverager() {
            _mean = 0.0;
            _count = 0L;
        }

        // undecided whether this method needs to be made thread-safe or not
        // seems that ought to be the responsibility of the IObservable (?)
        public double Add(double value) {
            double delta = value - _mean;
            _mean += (delta / (double)(++_count));
            return _mean;
        }
    }

    public static IObservable<double> ContinousAverage(this IObservable<double> source) {
        var averager = new ContinuousAverager();

        return source.Select(x => averager.Add(x));
    }
}
我会得到两个
IObservable
对象(
bids
avgOfBids
);一个基本上是来自my
MarketDataProvider
的所有市场出价流,另一个是这些出价的平均值流

比如说:

Bid    Avg Bid
1      1
2      1.5
1      1.33
2      1.5

我的
avgOfBids
对象似乎什么都没做。我错过了什么?我想我可能误解了
Average
实际上应该做什么。(这似乎也适用于
IObservable
上的所有聚合类扩展方法,例如
Max
Count
等)

在订阅bids事件流之后;您已经有效地阻止了任何其他观察者订阅(Subscribe返回IDisposable)

您必须定义另一个与刻度平行的可观测值,并订阅该值以对其进行平均

var ticksToAverage = Observable.FromEvent<QuoteEventArgs>(MarketDataProvider, "MarketTick");

 var bidsToAverage = ticksToAverage
      .Where(e => e.EventArgs.Quote.HasBid)
         .Select(e => e.EventArgs.Quote.Bid);


var avgOfBids = bidsToAverage.Average();
var avgOfBidsSubscription = avgOfBids.Subscribe( b => Console.WriteLine("Avg Bid: {0}", b)
                ); 
var ticksToAverage=Observable.FromEvent(MarketDataProvider,“MarketTick”);
var bidsToAverage=滴答声平均值
.Where(e=>e.EventArgs.Quote.HasBid)
.Select(e=>e.EventArgs.Quote.Bid);
var avgOfBids=bidsToAverage.Average();
var avgOfBidsSubscription=avgOfBids.subscription(b=>Console.WriteLine(“Avg Bid:{0}”,b)
); 

聚合方法不提供滚动最大/最小/计数/平均值等-它们在原始流完成时提供单个值。例如,如果您将代码更改为:

var avgOfBids = bids.Take(5).Average();
var avgOfBidsSubscription = avgOfBids.Subscribe(
    b => Console.WriteLine("Avg Bid: {0}", b)
);

然后,一旦进行了5次投标,它将显示它们的平均值。“平均”流也将完成。

另一种方法是使用.Scan()


为什么要阻止订阅?我愿意承认Rx经常让我困惑,但我不明白为什么会是这样。我相信这里的问题是完全不同的。我也有这样的印象,平均水平提供了一个运行的平均水平;根据你的回答,这似乎是错误的。至于拦网,你很可能是对的;因为Rx在引擎盖下使用常规CLR事件;多个参与方可以订阅一个活动而无需阻止。看来Jon的答案在这种情况下是正确的。不过,谢谢你的意见;我很感激!仅供参考,Rx中唯一使用CLR的部分是可观察的。FromEventJon,你知道Rx的文档来源吗?我已经浏览了MSDN和Rx团队的博客,但没有结果。@Pierreten:没有。我使用它附带的CHM文件和论坛提问。非常感谢!我想这是有道理的;不过,我希望MSDN有更多关于这些方法的文档。无论如何,我能够通过自己编写一个简单的实现来获得我想要的行为。你知道我写的东西(在我更新的答案中)是否已经存在吗?某种程度上说,是一个连续的分析库?@Dan:我相信如果你很狡猾的话,只需使用扫描和选择,你就可以逃脱。。。让Scan返回一个元组(count,total),然后选择total/count。是的,这确实是一个聪明的方法。乔恩·斯基特在他的一篇评论中提出了同样的观点。我仍然认为有一个
continuousstandarddiation
方法会很方便,或者像
ContinuousStatistics
这样的方法,它返回一个
IObservable
,其中
Statistics
是一个
struct
,包括均值、方差、标准差等。@Dan:看看这个实现:
var avgOfBids = bids.Take(5).Average();
var avgOfBidsSubscription = avgOfBids.Subscribe(
    b => Console.WriteLine("Avg Bid: {0}", b)
);
bids.Scan(new { sum = .0, count = 0 }, 
          (agg, x) => new { sum = agg.sum + x, count = agg.count + 1 })
    .Select(agg => agg.sum / agg.count)