从最近的两个变速源

时间:2016-10-21 11:14:31

标签: .net system.reactive reactive-programming

我想要实现以下结果:

L --1---3---4---5---6---7---8-
R ---A--------B--CDE-FG--H---I

O ---A--------B--C--E---G---H-
  ---1--------4--5--6---7---H-

所以基本上我有两个相对速度随时间变化的来源。结果应忽略有时L元素,有时忽略R元素。如何构建那种RX?

我尝试使用Joins,Sample,WithLatestFrom,Distincts等。但我总是可以忽略来自L来源但不是R的某些元素。 我试图在C#中实现它,但任何语言答案都会有所帮助。

3 个答案:

答案 0 :(得分:2)

您似乎正在寻找ZipLatest实施。见Does my "zipLatest" operator already exist?

修改

如果你想要一个实现,而不下载一个库,我认为这样可行:

public static IObservable<Tuple<T1, T2>> ZipLatest<T1, T2>(this IObservable<T1> left, IObservable<T2> right)
{
    return Observable.Defer(() =>
    {
        var leftSubject = new BehaviorSubject<bool>(false);
        var rightSubject = new BehaviorSubject<bool>(false);

        return left.Publish(_left =>
            right.Publish(_right =>
            {
                return Observable.CombineLatest(
                    _left,
                    _right,
                    _left.Select(_ => true).Merge(leftSubject),
                    _right.Select(_ => true).Merge(rightSubject), 
                    (l, r, l_bool, r_bool) => Tuple.Create(l_bool, r_bool, l, r)
                )
                    .Where(t => t.Item1 && t.Item2)
                    .Select(t => Tuple.Create(t.Item3, t.Item4))
                    .Do(_ =>
                    {
                        leftSubject.OnNext(false);
                        rightSubject.OnNext(false);
                    });
            })
        );
    });

针对@ Enigmativity的测试代码(已修改)运行...

void Main()
{
    var L = new Subject<int>();
    var R = new Subject<char>();

    var O = L.ZipLatest(R)
        .Select(t => new { l = t.Item1, r = t.Item2});

    O.Subscribe(o => Console.WriteLine($"{o.l}{o.r}"));

    L.OnNext(1);
    R.OnNext('A');
    L.OnNext(3);
    L.OnNext(4);
    R.OnNext('B');
    L.OnNext(5);
    R.OnNext('C');
    R.OnNext('D');
    R.OnNext('E');
    L.OnNext(6);
    R.OnNext('F');
    R.OnNext('G');
    L.OnNext(7);
    R.OnNext('H');
    L.OnNext(8);
    R.OnNext('I');
}

...你得到了正确的结果:

1A
4B
5C
6E
7G
8H

答案 1 :(得分:1)

这是我现在的尝试;我稍后会在编译器中尝试这个!

跟踪通过最新组合发送的最后一个值,并确保在应用操作之前每个值都是唯一的。将此操作定义为扩展方法。

public static IObservable<C> ZipLatest<A, B, C>(
    this IObservable<A> sourceA,
    IObservable<B> sourceB,
    Func<A, B, C> op) 
{
    IObservable<Tuple<A, B>> combined = sourceA.CombineLatest(
            sourceB, (a, b) => Tuple.Create(a, b));
    Tuple<A, B> last = null;
    return combined.Where(curr => 
    {
        if (last == null || (last.Item1 != curr.Item1 && last.Item2 != curr.Item2))
        {
            last = curr;
            return true;
        }
        return false;
    }).Select(curr => op(curr.Item1, curr.Item2));
}

答案 2 :(得分:0)

你所要求的似乎没有规则。您需要能够始终如一地描述来自LR的值会发生什么。

这是我能得到的最接近的地方:

var L = new Subject<int>();
var R = new Subject<char>();

var O = L.Select(l => R.Select(r => new { r, l })).Switch();

O.Subscribe(o => Console.WriteLine($"{o.l}{o.r}"));

L.OnNext(1);
R.OnNext('A');
L.OnNext(3);
L.OnNext(4);
R.OnNext('B');
L.OnNext(5);
R.OnNext('C');
R.OnNext('D');
R.OnNext('E');
L.OnNext(6);
R.OnNext('F');
R.OnNext('G');
L.OnNext(7);
R.OnNext('H');
L.OnNext(8);
R.OnNext('I');

那给了我:

1A
4B
5C
5D
5E
6F
6G
7H
8I

此外,从您的大理石图表中,不清楚'F'6是否排在第一位。您需要澄清价值顺序和组合流的规则。