C# 如何在移动中生成IObservable索引增量?

C# 如何在移动中生成IObservable索引增量?,c#,linq,system.reactive,set-difference,C#,Linq,System.reactive,Set Difference,我有两个数据源。 其中一个是缓存列表,另一个是通过IObservable推送的新数据 我想使用Rx找出需要对缓存列表A执行哪些操作,以使其顺序和内容与新数据相同 我正在寻找一个函数,它接受IEnumerable a和IObservable b,并返回一个可观察的在a上推送操作(插入和删除),使其与b相同,而无需等待b完成。 注意:我知道我不能修改列表或可观察。我不想 我只想知道,一旦这些操作被知道,什么样的操作,以什么样的顺序将把一个在顺序和顺序上与a相同的假设列表变成一个在顺序和顺序上与B相同

我有两个数据源。
其中一个是缓存列表,另一个是通过
IObservable
推送的新数据

我想使用Rx找出需要对缓存列表A执行哪些操作,以使其顺序和内容与新数据相同

我正在寻找一个函数,它接受
IEnumerable a
IObservable b
,并返回一个可观察的
a
上推送操作(插入和删除),使其与
b
相同,而无需等待
b
完成。

注意:我知道我不能修改列表或可观察。我不想

我只想知道,一旦这些操作被知道,什么样的操作,以什么样的顺序将把一个在顺序和顺序上与a相同的假设列表变成一个在顺序和顺序上与B相同的列表

a
b
都是唯一的,并且是经过排序的,
T
实现了
i可比较的
i可比较的

目标是找到一系列将a转换为B的删除/插入操作。想想a是缓存数据源,B是新数据,我想知道如何在不重新加载的情况下将这些更新转换为网格。

在两个源中对行进行排序

我希望输出是形式的

[(0, true), (1, true), (0, false), (3, false), (4, true), (5, true)]
稍后,我将按布尔标志对这些操作进行分组:

deleted:  [0, 3]
inserted: [0, 1, 4, 5]
这可以翻译成人类语言

  • 删除A0和A3:

    A=[150,100,70,30,20]=[100,70,20]

  • 将B0、B1、B4、B5插入:

    A=[300200,100,70,6050,20]

  • 现在A和B是一样的

  • 要求 有几件重要的事情我要注意:

  • A是一个保证不会更改的列表。B是一个冷可观测的,需要一些时间才能完成,但很快就会产生第一个项目。因此,只要有足够的数据可用,就需要推送可观察的结果。

  • 项目保证在两个来源中都是唯一的,
    i可满足的

  • 项目是不可变的,保证在两个源中使用
    i可比较的
    进行降序排序

  • 最好对添加到B左侧的新项目进行优化。这是最常见的情况。但是,如果项目的时间戳是适当的(不会破坏排序),则项目可能会被删除或插入到任何其他位置。想想iPhone的摄像头

  • (*)如果可能的话,我对纯功能解决方案感兴趣

  • 伪码草图 我草拟了一个伪代码算法,它以命令式的方式实现了这一点

    我编造了
    Current
    MoveNext
    wait
    yield push
    语义,但这个想法应该有一定的意义

    IObservable<Tuple<int, bool>> IndexDelta(a, b)
    {
        var indexA = 0;
        var indexB = 0;
    
        while (true) {
            var headA = a.Current;
            var headB = b.Current; 
    
            if (headA == null && headB == null) {
                return yield break; // both sequences are over
            }
    
            var reportDeletion = () => {
                yield push Tuple.Create(indexA, false);
                await a.MoveNext(); // this one is fast
            }
    
            var reportInsertion = () => {
                yield push Tuple.Create(indexB, true);
                await b.MoveNext(); // can take a long time
            }
    
            if (headA == null) { // No source item at this position
                reportInsertion();
                continue;
            }
    
            if (headB == null) { // No fetched item at this position
                reportDeletion();
                continue;
            }
    
            switch (headB.CompareTo(headA)) {
                case 0:
                    yield continue;
                    break;
                case 1: // Fetched item is newer than source item
                    reportInsertion();
                    break; 
                case -1: // Source item is newer than fetched item
                    reportDeletion();
                    break; 
            }
    
            indexA++;
            indexB++;
        }
    } 
    
    IObservable IndexDelta(a,b)
    {
    var indexA=0;
    var-indexB=0;
    while(true){
    var headA=a.电流;
    var headB=b.电流;
    if(headA==null&&headB==null){
    return yield break;//两个序列都结束了
    }
    var reportDeletion=()=>{
    产生push Tuple.Create(indexA,false);
    等待a.MoveNext();//这个很快
    }
    var reportInsertion=()=>{
    产生push Tuple.Create(indexB,true);
    等待b.MoveNext();//可能需要很长时间
    }
    如果(headA==null){//此位置没有源项
    reportInsertion();
    继续;
    }
    如果(headB==null){//此位置没有获取的项
    报告删除();
    继续;
    }
    开关(头B.比较器至(头A)){
    案例0:
    产量继续增长;
    打破
    案例1://获取的项比源项新
    reportInsertion();
    打破
    案例-1://源项比获取的项新
    报告删除();
    打破
    }
    indexA++;
    indexB++;
    }
    } 
    
    我相信您可以实现与
    主题
    非常类似的功能。但是,我不想继续使用这个解决方案,因为我想知道是否有可能纯粹通过组合Rx函数来解决它,例如
    Aggregate
    Zip
    combinelateest

    你的想法是什么?

    似乎有效

    void Main()
    {
        var a = new int?[] {150, 100, 70, 30, 20 };
        var b = new int?[] {300, 200, 100, 70, 60, 50, 20 };
        var result = IndexDelta(a, b);
        result.Dump();
    }
    
    // Define other methods and classes here
    IObservable<Tuple<int, bool>> IndexDelta(IEnumerable<int?> a, IEnumerable<int?> b)
    {
        var observable = Observable.Create<Tuple<int, bool>>(o => {
            var indexA = 0;
            var indexB = 0;
            var aEnumerator = a.GetEnumerator();
            var bEnumerator = b.GetEnumerator();
            var aHasNext = aEnumerator.MoveNext();
            var bHasNext = bEnumerator.MoveNext();
    
            while(true) {
                if (aHasNext == false && bHasNext == false) {
                    "Completed".Dump();
                    o.OnCompleted(); // both sequences are over
                    break;
                }
    
                var headA = aEnumerator.Current;
                var headB = bEnumerator.Current; 
    
                headA.Dump("A");
                headB.Dump("B");
    
                Action reportDeletion = () => {
                    o.OnNext(Tuple.Create(indexA, false));
                    aHasNext = aEnumerator.MoveNext(); // this one is fast
                };
                Action reportInsertion = () => {
                    o.OnNext(Tuple.Create(indexB, true));
                    bHasNext = bEnumerator.MoveNext(); // can take a long time
                };
    
                if (headA == null) { // No source item at this position
                    reportInsertion();
                    continue;
                }
    
                if (headB == null) { // No fetched item at this position
                    reportDeletion();
                    continue;
                }   
    
                switch (headB.Value.CompareTo(headA.Value)) {
                    case 0:     
                        aHasNext = aEnumerator.MoveNext();
                        bHasNext = bEnumerator.MoveNext();
                        indexA++;
                        indexB++;
                        break;
                    case 1: // Fetched item is newer than source item
                        reportInsertion();
                        indexB++;
                        break; 
                    case -1: // Source item is newer than fetched item
                        reportDeletion();
                        indexA++;
                        break; 
                }           
            }
            return Disposable.Empty;
        });     
        return observable;
    } 
    
    void Main()
    {
    var a=新的整数?[{150,100,70,30,20};
    VarB=新的整数?[{30020010070,60,50,20};
    var结果=指数delta(a,b);
    result.Dump();
    }
    //在此处定义其他方法和类
    IObservable IndexDelta(IEnumerable a,IEnumerable b)
    {
    var observable=observable.Create(o=>{
    var indexA=0;
    var-indexB=0;
    var aEnumerator=a.GetEnumerator();
    var bEnumerator=b.GetEnumerator();
    var aHasNext=aEnumerator.MoveNext();
    var bHasNext=bEnumerator.MoveNext();
    while(true){
    if(aHasNext==false&&bHasNext==false){
    “已完成”。转储();
    o、 OnCompleted();//两个序列都结束了
    打破
    }
    var headA=分子电流;
    var headB=断路器电流;
    标题A.垃圾场(“A”);
    标题B.垃圾场(“B”);
    操作报告删除=()=>{
    o、 OnNext(Tuple.Create(indexA,false));
    aHasNext=aEnumerator.MoveNext();//这个很快
    };
    动作报告插入=()=>{
    o、 OnNext(Tuple.Create(indexB,true));
    bHasNext=贝努美特。
    
    IObservable<Tuple<int, bool>> IndexDelta(a, b)
    {
        var indexA = 0;
        var indexB = 0;
    
        while (true) {
            var headA = a.Current;
            var headB = b.Current; 
    
            if (headA == null && headB == null) {
                return yield break; // both sequences are over
            }
    
            var reportDeletion = () => {
                yield push Tuple.Create(indexA, false);
                await a.MoveNext(); // this one is fast
            }
    
            var reportInsertion = () => {
                yield push Tuple.Create(indexB, true);
                await b.MoveNext(); // can take a long time
            }
    
            if (headA == null) { // No source item at this position
                reportInsertion();
                continue;
            }
    
            if (headB == null) { // No fetched item at this position
                reportDeletion();
                continue;
            }
    
            switch (headB.CompareTo(headA)) {
                case 0:
                    yield continue;
                    break;
                case 1: // Fetched item is newer than source item
                    reportInsertion();
                    break; 
                case -1: // Source item is newer than fetched item
                    reportDeletion();
                    break; 
            }
    
            indexA++;
            indexB++;
        }
    } 
    
    void Main()
    {
        var a = new int?[] {150, 100, 70, 30, 20 };
        var b = new int?[] {300, 200, 100, 70, 60, 50, 20 };
        var result = IndexDelta(a, b);
        result.Dump();
    }
    
    // Define other methods and classes here
    IObservable<Tuple<int, bool>> IndexDelta(IEnumerable<int?> a, IEnumerable<int?> b)
    {
        var observable = Observable.Create<Tuple<int, bool>>(o => {
            var indexA = 0;
            var indexB = 0;
            var aEnumerator = a.GetEnumerator();
            var bEnumerator = b.GetEnumerator();
            var aHasNext = aEnumerator.MoveNext();
            var bHasNext = bEnumerator.MoveNext();
    
            while(true) {
                if (aHasNext == false && bHasNext == false) {
                    "Completed".Dump();
                    o.OnCompleted(); // both sequences are over
                    break;
                }
    
                var headA = aEnumerator.Current;
                var headB = bEnumerator.Current; 
    
                headA.Dump("A");
                headB.Dump("B");
    
                Action reportDeletion = () => {
                    o.OnNext(Tuple.Create(indexA, false));
                    aHasNext = aEnumerator.MoveNext(); // this one is fast
                };
                Action reportInsertion = () => {
                    o.OnNext(Tuple.Create(indexB, true));
                    bHasNext = bEnumerator.MoveNext(); // can take a long time
                };
    
                if (headA == null) { // No source item at this position
                    reportInsertion();
                    continue;
                }
    
                if (headB == null) { // No fetched item at this position
                    reportDeletion();
                    continue;
                }   
    
                switch (headB.Value.CompareTo(headA.Value)) {
                    case 0:     
                        aHasNext = aEnumerator.MoveNext();
                        bHasNext = bEnumerator.MoveNext();
                        indexA++;
                        indexB++;
                        break;
                    case 1: // Fetched item is newer than source item
                        reportInsertion();
                        indexB++;
                        break; 
                    case -1: // Source item is newer than fetched item
                        reportDeletion();
                        indexA++;
                        break; 
                }           
            }
            return Disposable.Empty;
        });     
        return observable;
    } 
    
    IObservable<Tuple<int, T, bool>> IndexDelta<T>(
        IObservable<T> first, IObservable<T> second
    )
        where T : IComparable, IEquatable<T>
    {
        return Observable.Create<Tuple<int, T, bool>> (o => {
            var a = first.ToEnumerable ().GetEnumerator ();
            var b = second.ToEnumerable ().GetEnumerator ();
    
            var indexA = -1;
            var indexB = -1;
    
            var hasNextA = true;
            var hasNextB = true;
    
            var headA = default(T);
            var headB = default(T);
    
            Action<bool> advanceA = (bool reportDeletion) => {
                if (reportDeletion) {
                    o.OnNext (Tuple.Create (indexA, headA, false));
                }
    
                if (hasNextA = a.MoveNext ()) {
                    indexA++;
                    headA = a.Current;
                }
            };
    
            Action<bool> advanceB = (bool reportInsertion) => {
                if (reportInsertion) {
                    o.OnNext (Tuple.Create (indexB, headB, true));
                }
    
                if (hasNextB = b.MoveNext ()) {
                    indexB++;
                    headB = b.Current;
                }
            };
    
            advanceA (false);
            advanceB (false);
    
            while (true) {
                if (!hasNextA && !hasNextB) {
                    o.OnCompleted ();
                    break;
                }
    
                if (!hasNextA) {
                    advanceB (true);
                    continue;
                } 
    
                if (!hasNextB) {
                    advanceA (true);
                    continue;
                } 
    
                switch (headA.CompareTo (headB)) {
                case 0:
                    advanceA (false);
                    advanceB (false);
                    break;
                case 1:
                    advanceA (true);
                    break; 
                case -1:
                    advanceB (true);
                    break; 
                }          
            }
    
            return Disposable.Create (() => {
                a.Dispose ();
                b.Dispose ();
            });
        });     
    }