问题描述
看看https://eprystupa.wordpress.com/2009/12/18/detecting-running-highlow-prices-using-reactive-extensions-for-net/,它有一个有趣的代码块:
var rnd = new Random();
var Feed = Observable.Defer(() =>
Observable.Return(Math.Round(30.0 + rnd.NextDouble(),2))
.Delay(TimeSpan.FromSeconds(1 * rnd.NextDouble())))
.Repeat();
// Daily low price Feed
double min = double.MaxValue;
var FeedLo = Feed
.Where(p => p < min)
.Do(p => min = Math.Min(min,p))
.Select(p => "New LO: " + p);
// Daily high price Feed
double max = double.MinValue;
var FeedHi = Feed
.Where(p => p > max)
.Do(p => max = Math.Max(max,p))
.Select(p => "New HI: " + p);
// Combine hi and lo in one Feed and subscribe to it
FeedLo.Merge(FeedHi).Subscribe(Console.WriteLine);
上面的方法还可以,并且可以完成工作,但是局部变量max
和min
意味着代码是非常具体的,而我想附加 NewLowHi 代码/指标到现有的IObservable<double>
就像https://github.com/fiatsasia/Financier一样:
public static IObservable<TSource> SimpleMovingAverage<TSource>(this IObservable<TSource> source,int period)
{
return source.Buffer(period,1).Select(e => e.Average());
}
创建自包含的NewLowHi指标的最佳实践是什么,我可以在不使用(或至少在内部隐藏)局部变量max
和min
的情况下进行订阅?
解决方法
您在WordPress网站上引用的代码存在一些缺陷。
由于他们创建def Delete(s,t):
list_t=list(t)
list_s=list(s)
while list_t!=list_s:
list_t.pop()
#list_t.pop()
return "".join(list_t)
print(Delete("hello","helloworld"))
的方式很受欢迎,因此每个订阅都将收到一组不同的数字。因此,<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<table class="table table-bordered" style="table-layout: fixed;">
<colgroup>
<col span="1" style="width: 20%;">
<col span="1" style="width: 40%;">
<col span="1" style="width: 20%; white-space: normal;">
<col span="1" style="width: 20%;">
<col span="1" style="width: 20%;">
</colgroup>
<tr>
<th>Year</th>
<th>Month</th>
<th>Savings</th>
<th>Savings for holiday!</th>
<th>Random Words</th>
</tr>
<tr id='haha'>
<td rowspan="3">2020</td>
<td rowspan="3">January</td>
<td rowspan="3">text in here should be long enough to take more than 1 row</td>
</tr>
<tr>
<td>$100</td>
<td>Hello</td>
</tr>
<tr>
<td>$200</td>
<td>There</td>
</tr>
</table>
</body>
和feed
的可观察变量将在不同的变量集上工作。
但是情况变得更糟。例如,如果对feedLo
进行了两次订阅,则将对feedHi
进行两次订阅,但是feedLo
仅有一个状态变量,这意味着输出的值将是最小值两种订阅的数量,而不是每种订阅的最低数量。
我将展示如何正确执行此操作,但是首先您的问题是关于如何封装状态的。方法如下:
feed
现在,min
源将IObservable<T> feed =
Observable
.Defer(() =>
{
int state = 42;
return Observable... // define your observable here.
});
用作其状态。我们可以继续使用上面的模式重写feed
。
Random
与feed
/ var feed =
Observable
.Defer(() =>
{
var rnd = new Random();
return
Observable
.Generate(
0,x => true,x => x,x => Math.Round(30.0 + rnd.NextDouble(),2),x => TimeSpan.FromSeconds(rnd.NextDouble()));
});
/ Observable.Generate
/ Defer
模式相比,我更喜欢使用Return
。
现在介绍如何获取最小值和最大值。
我想要一个Delay
,该值可以给我一个可订阅源的单一订阅的高值和低值。 Repeat
如下所示:
IObservable<(State state,double value)>
这是我可观察的:
State
现在,我可以调用public enum State
{
High,Low,}
并从源订阅的一次订阅中获得IObservable<(State state,double value)> feedHighLow(IObservable<double> source) =>
source.Publish(xs => Observable.Merge(
xs.Scan(Math.Min).DistinctUntilChanged().Select(x => (state: State.Low,value: x)),xs.Scan(Math.Max).DistinctUntilChanged().Select(x => (state: State.High,value: x))));
/ feedHighLow(feed)
值的流。 High
调用可确保对源的单一订阅,而Low
意味着我可以运行两个不同的可观察变量以分别获取最小值和最大值。
我得到这样的结果: