如何观察不可变列表NotifyCollectionChanged

本文关键字:不可变 列表 NotifyCollectionChanged 观察 何观察 | 更新日期: 2023-09-27 18:28:48

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

那很好。

但是如何处理不可变列表的更改?

例如:我有IObservable<ImmutableArray<int>>,这个蒸汽的序列可能是:

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

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

第三:3,4

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

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

第一:添加事件1、2、3、4、5

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

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

非常感谢。

如何观察不可变列表NotifyCollectionChanged

这可能是一种有点天真的方法,但这是你想要的吗?

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);
        }
    });

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

最好的解决方案应该是Levenstein距离。

计算过程大致如下:

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

  2. 计算Levenstein距离,得到矩阵。

  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++;
                }
            });
    }