How to push array elements asynchronously - rxjs

I'm looking for a simple way to push array elements asynchronously every second. This code works fine - it sends 2 and in a second 55:
Rx.Observable.from([2, 55])
.zip(Rx.Observable.interval(1000), x => x);
Is there a simpler way to do the same thing?
Thank you.

If you use rxjs v4, you can make use of Rx.Observable.generateWithAbsoluteTime. It is basically a for loop with varying time.
Or you could use interval like here :
Rx.Observable.interval(1000).take(yourArray.length).map(index => yourArray[index])
What I dont know is if it is simpler.

Use toArray()
Rx.Observable
.interval(1000)
.take(3)
.toArray()
.subscribe(x=>console.log(x))

Have a look at combineLatest and withLatestFrom but this really depends what you're trying to do.
By the way, using .zip in this situation is probably not ideal because .zip emits only when it has Nth item from all source Observables which is what you usually don't want.

Related

RxJS Observables: new request depending on previous result

How can I generate new values to an Observable or Subject depending on received values?
Example:
Let's say I have an Observable that emits one random number thanks to a web API.
If it is an even number, I want the Observable to emit another random number using the first one as a seed... and so on until I get an odd value.
Note that I don't know in advance how many requests I'm going to make.
Until now, I managed to do it with "weird", recursive methods, but I feel like there must be a much proper way to do this.
Seems like you can use expand() for this.
const source$ = /* some API call that returns an Observable */;
source$.pipe(
expand((previous: number) => previous % 2 === 0 ? source$ : EMPTY),
takeLast(1),
).subscribe(console.log);
This gives you only the last value (the first odd). If you want to get all the intermediate values as well just remove that takeLast(1).
Live demo: https://stackblitz.com/edit/rxjs-czomtm

rx, looking for something like takeUntilMap

Im trying to achieve following behaviour:
//----A--A----A--|-----------------------------------streams
//--B------------B---B--B-------------------------------
//----A--A----A--B---B--B-----------------------------output
in other words: I need to complete A-stream by B-stream and still be able to consume first B item, but I cant find the way to do that.
example jsfiddle.net/dismedia/qbyy5cvs we have numbers$ and operators$, I need to scan numbers until operator appears
You could use the following:
Observable.concat(obsA.takeUntil(obsB), obsB)
.subscribe(...)

Get last value from incomplete observable

There is an incomplete observable which can have or not have a replay of n values. I would like to get the last value from it - or just the next one if there is none yet.
This works for first available value with first() and take(1) (example):
possiblyReplayedIncomplteObservable.first().toPromise().then(val => ...);
But for the last value both last() and takeLast(1) wait for observable completion - not the desirable behaviour here.
How can this be solved? Is there a specific operator for that?
I had a solution for ReplaySubject(2) that 'drains' the sequence to get the latest element and if the sequence is empty simply takes the last element, yet, it was cumbersome and did not scale well (for example, if you decide to increase the replay size to 3). I then remembered that Replay/Behavior subjects tend to be hard to manage when they are piped. The simplest solution to that is to create a 'shadow' sequence and pipe your ReplaySubject into it (instead of creating it by transformation/operation on your ReplaySubject), hence:
var subject$ = new Rx.ReplaySubject(3);
var lastValue$ = new Rx.ReplaySubject(1);
subject$.subscribe(lastValue$); // short hand for subject$.subscribe(v => lastValue$.next(v))
lastValue$.take(1).toPromise().then(...);
========== Old solutions, ignoring the ReplaySubject(2) =================
After reading the comment below, the correct code is:
Rx.Observable.combineLatest(possiblyReplayedIncomplteObservable).take(1).subscribe(...)
and not
Rx.Observable.combineLatest(possiblyReplayedIncomplteObservable).subscribe(...)
This is due to the fact the promise is a "one time" observable. I think the toPromise() code resolves the result only on completion.
The take(1) will not affect your original stream since it operates on the new stream which is created by combineLatest.
And actually, the simplest way is:
possiblyReplayedIncomplteObservable.take(1).toPromise().then(...)

Accomplishing shareValue/shareBehavior

I have an Observable that is based on some events and at some point does some expensive computation. I would like to render the results from that Observable in multiple different places. If I naively subscribe to this Observable in two places I will end up doing the expensive computation twice. Here is a code snippet to drive my point home:
var s = new rx.Subject();
var o = s.map(x => { console.log('expensive computation'); return x });
o.subscribe(x => console.log('1: ' + x));
o.subscribe(x => console.log('2: ' + x));
s.next(42);
The output is:
expensive computation
1: 42
expensive computation
2: 42
I would like to perform the expensive computation in the map only once. share accomplishes this, but it makes it so late-arriving subscribers do not get the current value to render. In previous RxJS versions, shareValue allowed late-arriving subscribers to get the current value. However, it appears that this was renamed to shareBehavior in RxJS 5 and then removed altogether:
https://github.com/ReactiveX/rxjs/pull/588
https://github.com/ReactiveX/rxjs/pull/712
There is a long discussion in this issue where it was decided that they would 'Remove shareBehavior and shareReplay to prevent user confusion.' I don't understand what the potential for confusion was (so maybe that means I am one of the users saved by this decision?).
publishBehavior also looks promising but I don't fully understand publish and it seems like it adds more complexity than I need or want.
Anyway, I would like to know if there is a recommended way to accomplish this in RxJS 5. The migration doc doesn't provide any recommendations.
After some more research I've found that the behavior I've described can be implemented with
.publishBehavior(startValue).refCount().
This discovery is based on the fact that share() is an alias for publish().refCount(). I still don't fully understand publish() but this seems to have the desired effect in practice.
Similar is cache(1) (which is an alias for publishReplay(1).refCount()). It has a similar effect as publishBehavior(defaultValue).refCount() except that it does not start with a default value. So if no items have been emitted, new subscribers will not immediately receive a value.

How would I convert this Ruby hash to an array?

I have this data in a hash:
[{"total_time"=>"00:04:48.563044"}, {"total_time"=>"00:05:29.835918"}, {"total_time"=>"00:09:38.622569"}]
But I want this:
["00:04:48.563044", "00:05:29.835918", "00:09:38.622569"]
Needs to work with Ruby 1.8.7.
You might manage with this:
list.collect(&:values).flatten
There's a ton of ways to accomplish this. Let's break it down into the basic steps you need to accomplish:
Iterate over each item in the array of hashes
For each item, grab the time value
Reassemble those into a list
Since you want to grab the result for each item, not just look at it, you'll want to use map (or collect, they're actuality the same method). That will take care of steps 1 and 3. And step 2, by itself, is pretty easy. You just need to get the value for a key with item['total_time']. Put it all together, and you've got this:
times.map{ |time| time['total_time'] }
Speaking about a ton of ways to accomplish this:
a = [{"total_time"=>"00:04:48.563044"}, {"total_time"=>"00:05:29.835918"}, {"total_time"=>"00:09:38.622569"}]
p a.map(&:flatten).map(&:last)

Resources