2

I am trying to implement a scenario using Rx where I have two hot Observables. Stream 1 and Stream 2. Based on data of Stream 1 i need to start Stream 2 or Stop Stream 2. Then combine both the stream data into one using CombineLatest. Below id the code that i am able to come up with.

  1. Is there a better way to implement this?

  2. And How can i make it more generic like I will have Stream 1 and then Stream 2 .. n for each stream from 2 .. n there are condition Condition 2 .. n which utilizes data of Stream 1 to check if other stream needs to start or not and then combine all the data in CombineLatest manner

CODE:

        IDisposable TfsDisposable = null;

        // stream 1
        var hotObs = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1));


        // stream 2
        var hotObs2 = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1)).Publish();


        var observerHot =  hotObs.Do(a => 
        {
            // Based on Condition to start the second stream
            if (ConditionToStartStream2)
            {
                TfsDisposable = TfsDisposable ?? hotObs2.Connect();
            }
        })
        .Do(a => 
        {
            // Based on condition 2 stop the second stream
            if (ConditionToStopStream2)
            {
                TfsDisposable?.Dispose();
                TfsDisposable = null;
            }
        }).Publish();


        // Merge both the stream using Combine Latest
        var finalMergedData  = hotObs.CombineLatest(hotObs2, (a, b) => { return string.Format("{0}, {1}", a, b); });

        // Display the result
        finalMergedData.Subscribe(a => { Console.WriteLine("result: {0}", a);  });

        // Start the first hot observable
        observerHot.Connect();
Balraj Singh
  • 3,381
  • 6
  • 47
  • 82

1 Answers1

1

Have a play with this:

var hotObs = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1.0));
var hotObs2 = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(0.3));

var query =
    hotObs2.Publish(h2s =>
        hotObs.Publish(hs =>
            hs
                .Select(a => a % 7 == 0 ? h2s : Observable.Empty<long>())
                .Switch()
                .Merge(hs)));

This takes both observables and publishes them using an overload which publishes them within a lambda. It makes them hot within the scope of the lambda and prevents the need to muck around with managing the calls to .Connect().

Then I'm simply performing a conditional check (in this case is a even) and then returning the other stream and if not returning an empty stream.

Then the.Switch turns the IObservable<IObservable<long>> into a IObservable<long> by only taking vales from the latest inner observable.

Finally it is merging with the original hs stream.

With the example code above I get the following output:

0 
1 
2 
3 
1 
2 
3 
4 
5 
6 
7 
23 
24 
25 
8 
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • Hi, I tried using the above mentioned expression but on subscribing the Observable I am not getting any output stream data. Can you explain it further. – Balraj Singh Feb 12 '16 at 17:21
  • @BalrajSingh - I got an output, but it didn't behave as I was expecting - I've got something wrong. I think that this is going to be close to what you need though. I'll work on it some more shortly and provide an explanation. – Enigmativity Feb 12 '16 at 23:24
  • I do see a condition to start second stream. But there is no condition to end it. Will the second stream continue to run even when the results are not required? – Balraj Singh Feb 13 '16 at 03:42
  • @BalrajSingh - Sorry, forgot to ping. – Enigmativity Feb 13 '16 at 03:43
  • I was just going through the answer and playing around with it. Changed the condition to a % 7 == 0 the problem i am seeing is the it is not printing some of the values of stream 1. – Balraj Singh Feb 13 '16 at 03:54
  • @BalrajSingh - I just tried it and it seems fine to me. What's missing? – Enigmativity Feb 13 '16 at 03:55
  • Actually In the initial question I am having two hot observable Stream 1 decides when to start Stream 2 and Stop it. Stream 1 continues to send the data out and as and when data is received from stream 2 it is combined with stream 1. – Balraj Singh Feb 13 '16 at 03:56
  • @BalrajSingh - Yes, I read that but your use of `string.Format("{0}, {1}", a, b)` doesn't fit that model. If you're stopping the second stream there there's nothing to combine the `a` with. You need to be clearer on how you expect it to work. – Enigmativity Feb 13 '16 at 03:59
  • Actually string.Format("{0}, {1}", a, b) is just to see if the result from both the stream is coming or not. If Stream 2 is not sending the data value for it would be default value of out variable for now it is 0. Hence result from stream 1 will be appended with 0. – Balraj Singh Feb 13 '16 at 04:03
  • @BalrajSingh - But they need to then be the same type. I can't output both `a` & `b` sometimes and only `a` the rest of the time. The output would need to be either `IEnumerable` or `string`. What do you want? – Enigmativity Feb 13 '16 at 04:06
  • I will change string.Format("{0}, {1}", a, b) with a merger function which will merge Value of Stream 2 to Stream 1 value if result from Stream 2 is coming else send the value of Stream 1 as it is. – Balraj Singh Feb 13 '16 at 04:07
  • @BalrajSingh - That's easy. Just a `SelectMany`. One tick. – Enigmativity Feb 13 '16 at 04:10
  • @BalrajSingh - No, sorry, just a `.Merge()`. Updating answer now. – Enigmativity Feb 13 '16 at 04:13