7

I have an observable stream that produces values at inconsistent intervals like this:

------1---2------3----------------4--------------5---

And I would like to sample this but without any empty samples once the a value has been produced:

------1---2------3----------------4--------------5-----

----_----1----2----3----3----3----4----4----4----5----5

I obviously thought Replay().RefCount() could be used here to provide the last known value to Sample() but as it doesn't re-subscribe to the source stream it didn't work out.

Any thoughts on how I can do this?

PeterAllenWebb
  • 10,319
  • 3
  • 37
  • 44
Slugart
  • 4,535
  • 24
  • 32

1 Answers1

9

Assuming your source stream is IObservable<int> xs then and your sampling interval is Timespan duration then:

xs.Publish(ps => 
    Observable.Interval(duration)
        .Zip(ps.MostRecent(0), (x,y) => y)
        .SkipUntil(ps))

For a generic solution, replace the 0 parameter to MostRecent with default(T) where IObservable<T> is the source stream type.

The purpose of Publish is to prevent subscription side effects since we need to subscribe to the source twice - once for MostRecent and once for SkipUntil. The purpose of the latter is to prevent sampling values until the source stream's first event.

You can simplify this if you don't care about getting default values before the source stream's first event:

Observable.Interval(duration)
    .Zip(xs.MostRecent(0), (x,y) => y)

A related operator WithLatestFrom might also be of interest; this is coming to Rx in the next release. See here for details.

Slugart
  • 4,535
  • 24
  • 32
James World
  • 29,019
  • 9
  • 86
  • 120
  • I hadn't thought of using an interval stream as the trigger for sampling - nice. – Slugart May 11 '15 at 13:16
  • 1
    Btw, I edited the answer to return the element from the source stream and not the interval stream. – Slugart May 11 '15 at 13:29
  • Yes, saw that thx! That's what you get for coding in Notepad... :) – James World May 11 '15 at 13:30
  • I am not sure if the behavior is expected by @Slugart, but if your input stream has a higher rate than your output sequence sampling rate, you will loose some data. Let's say you want to output one item every 2 seconds but your input stream can sometimes have 1 item every second, only half of these items will be outputted. Shouldn't there be some kind of buffering in case of multiple items are received during the interval duration? – Absolom May 11 '15 at 17:18
  • He did ask for sampling explicitly, so I would imagine that is the behaviour he is expecting, still never hurts to check! – James World May 11 '15 at 23:42
  • @Absolom Yep, I don't mind losing input data. The input can arrive faster or slower than the sampling period. – Slugart May 12 '15 at 07:08