对于可观察数组中的每个值,获取一个数字数组,然后将所有结果合并为一个可观察数字数组。
我尝试了flatMap
和concatMap
的各种组合,但无法正确完成。
someFunction(): Observable<number[]> {
// Observable<string[]>
const strings = of(['a', 'b', 'c']);
let index = 0;
// Observable<number[]>
const numbers = strings.pipe(
flatMap(ids => ids.map(() => of([index++, index++, index++])))
);
return numbers; // [1, 2, 3, 4, 5, 6, 7, 8, 9]
}
答案 0 :(得分:0)
看看您的代码,似乎bars
发出了Bar[]
类型的实例,这是由于Observable fooIds
发出了ID数组的结果。
如果是这种情况,那么这里可能要注意两件事。
第一个是使用switchMap
。使用此运算符,您可以在发生源可观测到的另一发射后立即完成所有正在运行的可观测。
换句话说,如果fooIds
以非常快的顺序发出2个ID数组,或者与此同步,则bars
到第二个ID到达时还没有完成对第一个ID数组的处理,那么第一个将被忽略,仅第二个会被处理。如果要保留所有结果,则可能要考虑使用mergeMap
(又称flatMap
)而不是switchMap
。
第二件事是使用concatAll
。使用此运算符,您想要保留可观察到的源序列。产生的Observable将始终发出类型为bar[]
的单个实例,其中包含使用通过bars
的单个通知传递的ID检索到的所有fooIds
。
如果您要获得的结果是Bar
的单个数组,其中包含来自fooIds
的所有通知的所有项目,则可以考虑使用reduce
运算符,例如通过以下方式
reduce((acc, one: any) => {
acc = acc.concat(one);
return acc;
}, []),
在@hdk发表评论后更新了答案
这应该是使您的示例工作正常的代码
function someFunction(): Observable<number[]> {
// Observable<string[]>
const strings = of(['a', 'b', 'c']);
let index = 0;
// Observable<number[]>
const numbers = strings.pipe(
mergeMap(ids => ids.map(() => of([index++, index++, index++]))),
mergeMap(d => d) // flattens the Observable<Observable<number>> to Observable<number>
);
const numbersReduced = numbers
.pipe(
reduce((acc: Array<number>, one: Array<number>) => {
acc = acc.concat(one);
return acc;
}, new Array<number>()),
);
return numbersReduced// [1, 2, 3, 4, 5, 6, 7, 8, 9]
}
someFunction().subscribe(console.log)
关键是要认识到
mergeMap(ids => ids.map(() => of([index++, index++, index++])))
返回一个Observable<Observable<number>>
。
为什么?因为ids.map(....)
返回了Array
,即ObservableInput
。 mergeMap
需要一个返回ObservableInput
的函数作为输入,因此返回Array
的函数就足够了。如果在这种情况下,Array
自身包含其他Observable,那么您将得到我们正在目睹的Observable<Observable<number>>
返回类型。
其余部分应该或多或少简单明了。
在现实世界中,例如如果您正在处理http请求,则可以使用其他策略,例如使用forkJoin
。在这种情况下,代码就是这样
function someFunction(): Observable<number[]> {
// Observable<string[]>
const strings = of(['a', 'b', 'c']);
let index = 0;
const numbers = strings.pipe(
mergeMap(ids => {
const numberObservables = ids.map(() => of([index++, index++, index++]));
return forkJoin(numberObservables)
})
);
const numbersReduced = numbers
.pipe(
map(arrayOfArrayOfNumbers => arrayOfArrayOfNumbers
.reduce(
(acc: Array<number>, one: Array<number>) => {
acc = acc.concat(one);
return acc;
}, new Array<number>()
))
)
return numbersReduced// [1, 2, 3, 4, 5, 6, 7, 8, 9]
}
请注意,您仍在使用reduce
,但是这次是Array
reduce
方法,而不是我们使用的Observable
reduce
方法在以前的情况下。