How to convert Observable<string>[] to Observable<string[]>

Viewed 195

I’ve got an Observable that has an array of objects and I would like to convert them to a different object using a second observable. This is part of a larger project so to simplify this for my question I am going to have an observable that has an array of number and I would like to convert them to a string. I started with the following.

    const response$ = of({results: [1, 2, 3]});
    response$.pipe(
        map((response) => {
            return response.results.map((id) => {
                return id.toString();
            })
        })
    )
    .subscribe((response: string[]) => {
        console.log(response);
    })

The response in the subscribe will be an array of string as expected. Now I need to use a second observable to convert the number to string (again just to make the question simpler). So I replaced return id.toString() with return of(id.toString()) to simulate making a second call to an observable.

    const response$ = of({results: [1, 2, 3]});
    response$.pipe(
        map((response) => {
            return response.results.map((id) => {
                return of(id.toString());
            })
        }),
    )
    .subscribe((response: Observable<string>[]) => {
        
    })

Now the signature of the response is Observable<string>[] but I need the response to be string[] so I started reading about other RxJS operators and I ended up with the following.

    const response$ = of({results: [1, 2, 3]});
    response$.pipe(
        concatMap((response) => {
            return response.results.map((id) => {
                return of(id.toString());
            })
        }),
        concatAll()
    )
    .subscribe((response: string) => {
        console.log('bar', response);
    })

I used concatMap() and concatAll() because I need the call to the second observable to happen in sequence. The problem now is that my response is a string and I get three calls to the subscriber “1” “2” “3”. I need one response of string[]. Can someone explain how to take an Observable<string>[] and convert it to Observable<string[]> in my example?

1 Answers

I think what you're looking for is this:

const response$ = of({results: [1, 2, 3]});
response$.pipe(
    switchMap((response) => {
        // map array to observables and execute all with forkJoin
        return forkJoin(...response.results.map((id) => {
            return of(id.toString());
        }))
    })
)
.subscribe((response: string) => {
    console.log('bar', response);
})

however, this is going to execute in parallel. if you need sequential execution on the inner, you can use concat and reduce

const response$ = of({results: [1, 2, 3]});
response$.pipe(
    switchMap((response) => {
        // map array to observables and execute all with concat and collect results with reduce
        return concat(...response.results.map((id) => {
            return of(id.toString());
        })).pipe(reduce((acc, v) => acc.concat([v]), []))
    })
)
.subscribe((response: string) => {
    console.log('bar', response);
})

only thing to be careful of is to make sure response.results has items in it. may need a length check like:

if (!response.results.length)
  return of([])
Related