我希望通过在特定时间间隔内从元素移动到元素来迭代集合。因此,例如,此方法可以正常工作:
var a = new List<int> { 1, 2, 3, 4}.ToObservable();
var b = Observable.Interval(TimeSpan.FromSeconds(1));
var c = a.Zip(b, (l, r) => l);
c.Subscribe(x => Debug.WriteLine(x));
但我想使用列表中每个元素的值作为间隔,所以我使用的是这段代码:
var a = new List<int> { 1, 2, 3, 4}.ToObservable();
var b = a.Delay(x => Observable.Timer(TimeSpan.FromSeconds(x)));
b.Subscribe(x => Debug.WriteLine(x));
如此处所述http://blogs.msdn.com/b/rxteam/archive/2012/03/12/reactive-extensions-v2-0-beta-available-now.aspx“延迟的新重载允许指定(可选)订阅的延迟以及基于选择器函数的每个元素的延迟”。但是运行代码并不像预期的那样工作。它只是以1秒的间隔吐出列表的元素。像这样:
......(1秒) 1 ...(1秒) 2 ...(1秒) 3 ...(1秒) 4
而不是
......(1秒) 1 ......(2秒) 2 ......(3秒) 3 ......(4秒) 4
我错过了什么吗?
答案 0 :(得分:1)
这个怎么样:
new[] {1,2,3,4,5,}.ToObservable()
.Select(x => Observable.Return(x).Delay(TimeSpan.FromSeconds(x)))
.Concat();
右?您想将数字用作值以及延迟的时间量吗?
答案 1 :(得分:1)
这是一个解决方案,它在可枚举源上的迭代器仅在它再次等待之前一步(使用无限可枚举源序列):
static IObservable<T> ToObservableDelay<T>(
IEnumerable<T> source,
Func<T, TimeSpan> delaySelector,
IScheduler scheduler
)
{
return Observable.Create<T>(o =>
scheduler.ScheduleAsync(async (s, c) =>
{
try
{
foreach (var x in source)
{
await Task.Delay(delaySelector(x), c);
o.OnNext(x);
}
o.OnCompleted();
}
catch (TaskCanceledException) { /* ignore */ }
catch (Exception e)
{
o.OnError(e);
}
})
);
}
这里有一个带有无限发电机的小演示:
static IEnumerable<double> Uniform(Random rng)
{
while (true)
yield return rng.NextDouble();
}
static void Main(string[] args)
{
var source = Uniform(new Random());
Console.WriteLine("press any key to quit");
using (var subscription =
ToObservableDelay(source, TimeSpan.FromSeconds, Scheduler.Default)
.Subscribe(Console.WriteLine))
{
Console.ReadKey();
}
}
在RT应用程序中运行的简单演示代码:
var source = Uniform(new Random());
ToObservableDelay(source, TimeSpan.FromSeconds, Scheduler.Default)
.Take(10)
.Subscribe(x => Debug.WriteLine(x));
答案 2 :(得分:0)
我在尝试解决同样的问题时发现了这个问题。我的解决方案是使用Observable.Generator和IEnumerable的枚举器,如下所示:
public static IObservable<T> ToObservable<T>(this IEnumerable<T> source, TimeSpan time)
{
var enumerator = source.GetEnumerator();
var observable = Observable.Generate(
enumerator.Current,
_ => enumerator.MoveNext(),
_ => enumerator.Current,
_ => enumerator.Current,
_ => time);
return observable;
}
然后简单地调用此扩展方法:
var observable = Enumerable.Range(1, 10)
.ToObservable(TimeSpan.FromSeconds(1));
using (observable.Subscribe(Console.WriteLine))
{
Console.WriteLine("Press the Any key to abort");
Console.ReadKey();
}