Paul Milla Paul Milla - 3 days ago 4
C# Question

Observable<IEnumerable> get differences between sequence elements

I have an observable that emits a sequence of IEnumerables

1:

[1,2,3,4]


2:
[1,3,4]


3:
[1,5,6]


etc..

I want to try and create two observables from this:


  • One that emits an IEnumerable of newly added elements:



1:
[1,2,3,4]


2:
[]


3:
[5, 6]


etc..


  • One that emits an IEnumerable of newly removed elements:



1:
[]


2:
[2]


3:
[3,4]


etc..

Is there a way to do this using System.Reactive without having to rely on keeping a separate data structure to compare changes against?

Answer

It's fairly simple if you use Observable.Zip and Enumerable.Except to easily compare element n to element n-1.

public static class IObservableIEnumerableExtensions
{
    public static IObservable<IEnumerable<T>> GetAddedElements<T>(this IObservable<IEnumerable<T>> source)
    {
        return source.Zip(source.StartWith(Enumerable.Empty<T>()), (newer, older) => newer.Except(older));
    }

    public static IObservable<IEnumerable<T>> GetRemovedElements<T>(this IObservable<IEnumerable<T>> source)
    {
        return source.Zip(source.StartWith(Enumerable.Empty<T>()), (newer, older) => older.Except(newer));
    }
}

And here's some runner code:

var source = new Subject<IEnumerable<int>>();

var addedElements = source.GetAddedElements();
var removedElements = source.GetRemovedElements();

addedElements.Dump();   //Using Linqpad
removedElements.Dump(); //Using Linqpad

source.OnNext(new int[] { 1, 2, 3, 4 });
source.OnNext(new int[] { 1, 3, 4 });
source.OnNext(new int[] { 1, 5, 6 });