Doua Beri
Doua Beri

Reputation: 10949

Combination of reduce and scan with a subject

RxJS version: 5.5.2

I have an array const v = [1, 2, 3];

I want to be able to create a Subject from this array and act like an Observable until it consumes the 1, 2, 3 values. After that I want to act like a Subject.

Here is where I'm having trouble. I need to use reduce on initial values v = [1, 2, 3] then every time the Subject adds another value to use scan

Here is the code:

const v = [1, 2, 3];
const sub = new Subject<number>();
const observable = sub.pipe(
  startWith(0),
  concatMap(x => from(v)),
  scan((a, b) => { // or reduce
    return a + b;
  }, 0),
);
observable.subscribe(x => console.log(x));

If I'm using scan here this is printed on console

1
3
6

What I want to be printed is just last value 6. Replacing scan with reduce will do the job only if subject is completed(that way I can't send any more values in the future).

Then every time the subject sends a value sub.next(4); to print 10 and so on.

Upvotes: 1

Views: 256

Answers (1)

martin
martin

Reputation: 96891

You can use skipWhile() to skip the first N emissions from scan that you don't want:

import { Subject } from "rxjs/Subject";
import { from } from "rxjs/observable/from";
import { of } from "rxjs/observable/of";
import { merge, concatMap, scan, skipWhile, tap } from "rxjs/operators";

const v = [1, 2, 3];
let skipFirst;

const sub = new Subject<number>();

const observable = of(v).pipe(
  tap(arr => skipFirst = arr.length),
  concatMap(arr => from(arr)),
  merge(sub),
  scan((a, b) => { // or reduce
    return a + b;
  }, 0),
  skipWhile(() => --skipFirst > 0),
);
observable.subscribe(x => console.log(x));

sub.next(5);

This prints:

6
11

Upvotes: 1

Related Questions