如何观察不可变列表 INotifyCollectionChanged?

How to observe Immutable List NotifyCollectionChanged?

正如我们所知,我们可以使用 ObservableCollection 观察集合的变化。

没关系。

但是如何处理 ImmutableList 改变了?

对于 example:I 有 IObservable<ImmutableArray<int>> 并且此蒸汽的顺序可能是:

第一个:1、2、3、4、5

第二个:1、2、3、4、5、6 <----(绑定到视图时可能会出现一些性能问题。)

第三名:3、4

有什么优雅的方法(或一些库)可以转换IObservable<ImmutableArray<int>> to ObservableCollection<int> ?

然后我们可以观察到ObservableCollection通知事件:

首先:添加事件1、2、3、4、5

第二:添加事件 6、7 <----(太棒了!)

第三:删除事件1、2、5、6

非常感谢。

这可能有点幼稚,但这是您的想法吗?

source
    .Subscribe(ia =>
    {
        var ia2 = ia.ToArray();
        var adds = ia2.Except(oc).ToArray();
        var removes = oc.Except(ia2).ToArray();
        foreach (var a in adds)
        {
            oc.Add(a);
        }
        foreach (var r in remove)
        {
            oc.Remove(r);
        }
    });

经过一些研究,我对自己的问题有了答案。

最好的解决方案应该是Levenshtein distance

计算过程大致如下:

  1. 确定插入删除替代成本。 (插入=1,删除=1,替换=2)

  2. 计算编辑距离得到矩阵

  3. 最短路径和对齐的回溯矩阵。 (很像A*寻路,生成矩阵时设置回溯点,回溯后得到最短路径)

因此这个问题可以关闭了。

我实际上写了一个 nuget 包,它会自动为你做这件事

https://github.com/Weingartner/ReactiveCompositeCollections

部分代码使用不可变列表之间的差异来生成 ObservableCollection 更改事件。

执行差异的代码使用 DiffLib

    public static IObservable<List<DiffElement<T>>> 
        ChangesObservable<T>
         ( this ICompositeList<T> source
         , IEqualityComparer<T>comparer = null 
         )
    {
        return source
            .Items // IObservable<ImmutableList<T>>
            .StartWith(ImmutableList<T>.Empty)
            .Buffer(2, 1).Where(b => b.Count == 2)
            .Select(b =>
                    {
                        var sections = Diff.CalculateSections(b[0], b[1], comparer);
                        var alignment = Diff.AlignElements
                            (b[0], b[1], sections, new BasicReplaceInsertDeleteDiffElementAligner<T>());
                        return alignment.ToList();
                    });
    }

在另一种方法中可以转换成 ObservableCollection

    internal ReadOnlyObservableCollection
        ( ICompositeList<T> list
        , System.Collections.ObjectModel.ObservableCollection<T> collection
        , IEqualityComparer<T> eq
        ) : base(collection)
    {
        _List = list;
        _Collection = collection;

        _Disposable = list.ChangesObservable(eq)
            .Subscribe(change =>
            {
                int i = 0;
                foreach (var diff in change)
                {
                    switch (diff.Operation)
                    {
                        case DiffOperation.Match:
                            break;
                        case DiffOperation.Insert:
                            _Collection.Insert(i, diff.ElementFromCollection2.Value);
                            break;
                        case DiffOperation.Delete:
                            _Collection.RemoveAt(i);
                            i--;
                            break;
                        case DiffOperation.Replace:
                            _Collection[i] = diff.ElementFromCollection2.Value;
                            break;
                        case DiffOperation.Modify:
                            _Collection[i] = diff.ElementFromCollection2.Value;
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                    i++;
                }
            });
    }