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