WinRT上的Rx:随着时间的推移迭代收集

时间:2013-09-26 15:04:27

标签: c# windows-runtime system.reactive

我希望通过在特定时间间隔内从元素移动到元素来迭代集合。因此,例如,此方法可以正常工作:

        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

我错过了什么吗?

3 个答案:

答案 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();
}