Rx:运算符,用于从Observable流中获取第一个和最近的值

时间:2012-07-27 18:17:59

标签: system.reactive

对于基于Rx的变更跟踪解决方案,我需要一个运算符,它可以在可观察的序列中获取第一个和最近的项目。

我如何编写一个生成以下大理石图的Rx运算符(注意:括号仅用于排列项目...我不确定如何最好地在文本中表示 ):

     xs:---[a  ]---[b  ]-----[c  ]-----[d  ]---------|
desired:---[a,a]---[a,b]-----[a,c]-----[a,d]---------| 

3 个答案:

答案 0 :(得分:5)

使用与@Wilka相同的命名,您可以使用以下扩展名,这有点不言自明:

public static IObservable<TResult> FirstAndLatest<T, TResult>(this IObservable<T> source, Func<T,T,TResult> func)
{
    var published = source.Publish().RefCount();
    var first = published.Take(1);        
    return first.CombineLatest(published, func);
}

请注意,它不一定返回Tuple,而是为您提供在结果上传递选择器函数的选项。这使其与基础主要操作(CombineLatest)保持一致。这显然很容易改变。

用法(如果您想在结果流中使用元组):

Observable.Interval(TimeSpan.FromSeconds(0.1))
          .FirstAndLatest((a,b) => Tuple.Create(a,b))
          .Subscribe(Console.WriteLine);

答案 1 :(得分:2)

试试这个:

public static IObservable<Tuple<T, T>> FirstAndLatest<T>(
    this IObservable<T> source)
{
    return
        source
            .Take(1)
            .Repeat()
            .Zip(source, (x0, xn) => Tuple.Create(x0, xn));
}

简单,是吗?


或者,作为共享基础资源的替代方法,请尝试以下方法:

public static IObservable<Tuple<T, T>> FirstAndLatest<T>(
    this IObservable<T> source)
{
    return
        source.Publish(
            s =>
                s.Take(1)
                .Repeat()
                .Zip(s, (x0, xn) => Tuple.Create(x0, xn)));
}

糟糕!抓住这个。它不起作用。它基本上保持产生一对最新值。像这样的发布是行不通的。最初的实施是最好的。

答案 2 :(得分:1)

我怀疑有更好的方法(我不喜欢使用Do),但你可以像这样创建一个运算符

public static IObservable<Tuple<T, T>> FirstAndLatest2<T>(this IObservable<T> source)
{
    return Observable.Defer(() => {
        bool hasFirst = false;
        T first = default(T);

        return source
            .Do(item =>
            {
                if (!hasFirst)
                {
                    hasFirst = true;
                    first = item;
                }
            })
            .Select(current => Tuple.Create(first, current));
    });
}

然后你会像这样使用它:

Observable.Interval(TimeSpan.FromSeconds(0.1))
    .FirstAndLatest()
    .Subscribe(Console.WriteLine);