我正在.NET中学习rx,我有以下要求:
因此,给出示例数据:
using System;
using System.Reactive.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var results = new[]
{
"right", //1
"left", //2
"right", //3
"right", //4
"left", //5
"right", //6
"right", //7
"right", //8
"left" //9
};
var observable = Observable.Generate(0,
x => x < results.Length,
x => x + 1,
x => results[x],
x =>
TimeSpan.FromSeconds(1)).Timestamp();
observable.Subscribe(...);
Console.ReadKey();
}
}
}
结果应为:
right //1
left //2
right //3
left //5
right //6
right //8
left //9
字符串4已被跳过,因为它距最后一个“右”仅1秒,字符串7也是如此。但是,字符串8未被跳过,因为字符串6有2秒。
可能的解决方案:
我试图使用窗口函数来跳过条目,但这会跳过所有字符串,即使它们的值不同:
observable.Publish(ps =>
ps.Window(() => ps.Delay(TimeSpan.FromSeconds(2)))
.SelectMany(x => x.Take(1))).Subscribe(f => Console.WriteLine(f.Value));
我还尝试将时间戳添加到每个值,并在DistinctUntilChanged()EqualityComparer中进行检查,但这似乎也无法按预期工作。
答案 0 :(得分:2)
我还没有测试过这段代码,但是您已经有了大致的认识。
source
.Select(x => (str: x, timestamp: DateTime.Now))
.Scan((last: (str: "", timestamp: DateTime.MinValue), next: (str: "", timestamp: DateTime.MinValue)),
(state, val) =>
(last: (str: state.next.str, timestamp: state.next.timestamp), next: (str: val.str, timestamp: val.timestamp))
)
.Where(x => (x.next.str != x.last.str) || (x.next.timestamp - x.last.timestamp) > TimeSpan.FromSeconds(2))
.Select(x=>x.next.str);
答案 1 :(得分:2)
这比我想象的要棘手,因为有三重情况(右,右,右相隔一秒钟)。在这里无法使用直.Zip
。
这类似于Sentinel的答案,并且可以正确处理三重情况:
source
.Timestamp()
.Scan((state, item) => state == null || item.Timestamp - state.Timestamp > TimeSpan.FromSeconds(2) || state.Value != item.Value
? item
: state
)
.DistinctUntilChanged()
.Select(t => t.Value);
说明:
.Timestamp()
将每封邮件及其到达的时间戳包装起来.Scan(1 arg)
如果2秒钟内出现重复,则会重复上一条消息,否则发出新消息.DistinctUntilChanged()
删除重复的消息,这是因为.Scan
发出了两次旧消息.Select
删除时间戳记。答案 2 :(得分:0)
嗯..听起来像observable.DistinctUntilChanged
可以检测到不同的事件,但是通过CombineLatest
与observable.Debounce
合并在一起也可以得到重复。 >
这将涵盖基础知识,但是我不确定如果在比反跳时间更长的时间之后出现了与之前不同的项目,将会发生什么情况。源DistinctUntilChanged和Debounce运算符都会在“同时”,我不确定此时的CombineLatest会做什么。发生变化是,您将两次获得此类事件(在很短的时间内就会发生同一事件),因此您需要再次将其重复数据删除。
如果您愿意添加某种时间戳记,那么还有一种相当明确的方法可以做到这一点,尽管我不确定这样做是否真的更简单。
您应该能够通过简单地使整个gethashcode类返回0并等于equals返回false来实现神奇的ObjectThatIsAlwaysDifferent。
这应该返回与上一个命令具有不同命令的事件,或者与之前相同但在比推迟时间更长的时间之后发生的事件。
现在考虑一下,应该可以通过压缩当前值和先前值来非常简单地做到这一点:
应该是这样。和往常一样,做同一件事的方法不止一种。