Net Dots

.Net and programming in general

Making list navigation responsive using Reactive Extensions-part 3 (CombineVeryLatest)

Let’s take a look at creating a variation of CombineLatest operator which we used as a part of SampleResponsive extension in the previous article in the series. We needed an operator that would combine two most recent elements from source observables on one-to-one basis (in the combined observable, no element from any of the sources would appear twice). CombineLatest almost makes the first part of this requirement, and we just need to filter out extra pairs that contain duplicate elements.

The first trick we will use is a Select overload which allows us to generate id’s attached to our elements. The resulting observable contains pairs of tuples, each containing both the real value and id:

                 return  Observable .CombineLatest(
                     leftSource.Select(Tuple .Create<TLeft, int >),
                     rightSource.Select(Tuple .Create<TRight, int >),
                         (x, y) => new  { x, y })
  

Now, we can introduce a “state” to our extension which would track the latest id’s and also make possible to filter the oncoming elements comparing to that id’s. We update the state by inserting a side-effecting extension .Do right after the filter:

         public  static  IObservable <TResult> CombineVeryLatest<TLeft, TRight, TResult>(this  IObservable <TLeft> leftSource,
           IObservable <TRight> rightSource, Func <TLeft, TRight, TResult> selector)
         {
             int  l = -1, r = -1;
             return  Observable .CombineLatest(
                 leftSource.Select(Tuple .Create<TLeft, int >),
                 rightSource.Select(Tuple .Create<TRight, int >),
                     (x, y) => new  { x, y })
                 .Where(t => t.x.Item2 != l && t.y.Item2 != r)
                 .Do(t => { l = t.x.Item2; r = t.y.Item2; })
                 .Select(t => selector(t.x.Item1, t.y.Item1));
         }
  

This is the same signature as CombinedLatest has. The only thing left is to isolate the state (l and r variables) within the extension from multiple subscribers. This is usually done by using the .Defer() method (which would also make our observable Cold):

         public  static  IObservable <TResult> CombineVeryLatest<TLeft, TRight, TResult>(this  IObservable <TLeft> leftSource,
           IObservable <TRight> rightSource, Func <TLeft, TRight, TResult> selector)
         {
             return  Observable .Defer(() =>
             {
                 int  l = -1, r = -1;
                 return  Observable .CombineLatest(
                     leftSource.Select(Tuple .Create<TLeft, int >),
                     rightSource.Select(Tuple .Create<TRight, int >),
                         (x, y) => new  { x, y })
                     .Where(t => t.x.Item2 != l && t.y.Item2 != r)
                     .Do(t => { l = t.x.Item2; r = t.y.Item2; })
                     .Select(t => selector(t.x.Item1, t.y.Item1));
             });
         }
 

All done! This extension is useful in situations when you need to combine pairs of values that “expire” after being combined.

Advertisements

February 9, 2011 - Posted by | Uncategorized

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: