在Rx中实现滑动窗口的问题 [英] Trouble Implementing a Sliding Window in Rx

查看:156
本文介绍了在Rx中实现滑动窗口的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为响应式扩展创建了一个SlidingWindow运算符,因为我想轻松监视滚动平均值之类的事情.作为一个简单的示例,我想订阅以听取鼠标事件,但是每次有一个事件我都想接收最后三个(而不是等待每三个事件接收最后三个).这就是为什么我发现Window重载似乎无法为我提供开箱即用的东西的原因.

I created a SlidingWindow operator for reactive extensions because I want to easily monitor things like rolling averages, etc. As a simple example, I want to subscribe to hear mouse events, but each time there's an event I want to receive the last three (rather than waiting for every third event to receive the last three). That's why the Window overloads I found don't seem to give me what I need out of the box.

这是我想出的.考虑到它频繁的List操作,我担心它可能不是最有效的解决方案:

This is what I came up with. I fear that it might not be the most performant solution, given its frequent List operations:

public static IObservable<List<T>> SlidingWindow<T>(this IObservable<T> seq, int length)
{
    var seed = new List<T>();

    Func<List<T>, T, List<T>> accumulator = (list, arg2) =>
    {
        list.Add(arg2);

        if (list.Count > length)
            list.RemoveRange(0, (list.Count - length));

        return list;
    };

    return seq.Scan(seed, accumulator)
                .Where(list => list.Count == length);
}

可以这样称呼:

var rollingSequence = Observable.Range(1, 5).SlidingWindow().ToEnumerable();

但是,令我惊讶的是,没有收到预期的结果

However, to my great surprise, instead of receiving the expected results

1,2,3
2,3,4
3,4,5

我收到结果

2,3,4
3,4,5
3,4,5

任何见解将不胜感激!

推荐答案

试试看-我必须坐下来考虑一下它的相对性能,但这至少是 一样好,而且更易于阅读:

Try this instead - I'd have to sit and have a think about it's relative performance, but it's at least likely as good, and way easier to read:

public static IObservable<IList<T>> SlidingWindow<T>(
       this IObservable<T> src, 
       int windowSize)
{
    var feed = src.Publish().RefCount();    
    // (skip 0) + (skip 1) + (skip 2) + ... + (skip nth) => return as list  
    return Observable.Zip(
       Enumerable.Range(0, windowSize)
           .Select(skip => feed.Skip(skip))
           .ToArray());
}

测试装备:

var source = Observable.Range(0, 10);
var query = source.SlidingWindow(3);
using(query.Subscribe(Console.WriteLine))
{               
    Console.ReadLine();
}

输出:

ListOf(0,1,2)
ListOf(1,2,3)
ListOf(2,3,4)
ListOf(3,4,5)
ListOf(4,5,6)
...

顺便说一句,自从不做一次就被烧死后,我就发现自己强迫自己.Publish().RefCount() ...我认为这不是严格要求的.

As an aside, I find myself compulsively .Publish().RefCount()ing ever since being burned once by not doing it...I don't think it's strictly required here, tho.

编辑yzorg:

如果像这样扩展方法,您将更清楚地看到运行时行为:

If you augment the method like so, you'll see the runtime behavior more clearly:

public static IObservable<IList<T>> SlidingWindow<T>(
    this IObservable<T> src, 
    int windowSize)
{
    var feed = src.Publish().RefCount();    
    // (skip 0) + (skip 1) + (skip 2) + ... + (skip nth) => return as list  
    return Observable.Zip(
    Enumerable.Range(0, windowSize)
        .Select(skip => 
        {
            Console.WriteLine("Skipping {0} els", skip);
            return feed.Skip(skip);
        })
        .ToArray());
}

这篇关于在Rx中实现滑动窗口的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆