![](/img/trans.png)
[英]Learning Rx: How can I parse an observable sequence of characters into an observable sequence of strings?
[英]Learning Rx: How to use .Scan on the output of .Window for an observable sequence of bool values
我有一系列真假值,如此
var alternatingTrueFalse = Observable.Generate(
true,
_ => true,
x => !x,
x => x,
_ => TimeSpan.FromMilliseconds(new Random().Next(2000)))
.Take(20).Publish();
alternatingTrueFalse.Connect();
var buffered = alternatingTrueFalse
.Buffer(TimeSpan.FromMilliseconds(500))
.Subscribe(x => Console.WriteLine($"{TimeStamp} {string.Join(",", x)}"));
我想用500毫秒(最大)窗口/緩沖區來查看序列。 如果在一個這樣的窗口中只有一個真值(沒有別的),我想翻轉一個開關(只需調用一個命令,現在打印到控制台)。 然后,當下一個假值到達時,我想要將開關向后翻轉並關閉原始序列的當前窗口/緩沖區並開始一個新的。
到目前為止,我已經想出了一種在Buffer上做到這一點的方法。 但是,緩沖區打開時間過長,始終為500毫秒。
var buffered = alternatingTrueFalse
.Buffer(TimeSpan.FromMilliseconds(500));
var output = buffered
.Subscribe(x => Console.WriteLine($"{TimeStamp} {string.Join(",", x)}"));
var isFlipped = buffered.Scan(false,
(x, y) =>
{
if (y.Count == 0)
{
return x;
}
return y.Count == 1 && y.First();
});
isFlipped.DumpTimes("Flipped");
我試圖弄清楚如何使用Window而不是Buffer來在第一個false之后將交換機翻轉回來。 但我似乎無法做到正確,我對Rx還不是很流利,也不確定如何使用windowOpening / Closing值。
原版的
2017-10-07 20:21:39.302 True,False // Rapid values should not flip the switch (actually they should flip a different switch)
2017-10-07 20:21:39.797 True // Flip the switch here
2017-10-07 20:21:40.302 False // Flip the switch back and close the current window
2017-10-07 20:21:40.797 True // Flip the switch here
2017-10-07 20:21:41.297
2017-10-07 20:21:41.798 False // Etc...
...
2017-10-07 20:21:43.297 True
2017-10-07 20:21:43.800 False,True // Example of a window that is open too long, because it is not closed immediately upon the false value
...
緩沖+掃描
2017-10-07 20:47:15.154 True
2017-10-07 20:47:15.163 - Flipped-->True
2017-10-07 20:47:15.659 False,True // Example of a window open too long
2017-10-07 20:47:15.661 - Flipped-->False
這是一個不使用Scan
方法的解決方案。
問題似乎是基於兩個條件關閉緩沖區 - 最大時間或特定值。 這是基於一個舊的答案
public static IObservable<IList<TSource>> BufferWithClosingValue<TSource>(
this IObservable<TSource> source,
TimeSpan maxTime,
TSource closingValue)
{
return source.GroupByUntil(_ => true,
g => g.Where(i => i.Equals(closingValue)).Select(_ => Unit.Default)
.Merge(Observable.Timer(maxTime).Select(_ => Unit.Default)))
.SelectMany(i => i.ToList());
}
示例用法是
alternatingTrueFalse.BufferWithClosingValue( TimeSpan.FromMilliseconds(500), false );
我建議不要基於其他運算符創建自定義運算符,因為它將占用更多的CPU和內存。
這是同一方法的干凈版本。
public static IObservable<IEnumerable<TValue>> BufferWithThrottle<TValue>(this IObservable<TValue> @this, int maxAmount, TimeSpan threshold)
{
var buffer = new List<TValue>();
return Observable.Create<IEnumerable<TValue>>(observer =>
{
var aTimer = new Timer();
void Clear()
{
aTimer.Stop();
buffer.Clear();
}
void OnNext()
{
observer.OnNext(buffer);
Clear();
}
aTimer.Interval = threshold.TotalMilliseconds;
aTimer.Enabled = true;
aTimer.Elapsed += (sender, args) => OnNext();
var subscription = @this.Subscribe(value =>
{
buffer.Add(value);
if (buffer.Count >= maxAmount)
OnNext();
else
{
aTimer.Stop();
aTimer.Start();
}
});
return Disposable.Create(() =>
{
Clear();
subscription.Dispose();
});
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.