问题描述
我想这更像是一个逻辑问题,而不是 RxJS 问题,但我不知道如何解决它。
[输入 1]
从城市流中,我将收到 1 或 2 个对象(城市 1 或城市 2 是测试装置)。
如果只有一种语言可用,则为 1 个对象,如果有两种语言,则为 2 个对象。
[输入 2] 我也有一个 selectedLanguage(“fr”或“nl”)
[算法] 如果对象的语言对应于 selectedLanguage,我将选择城市。当我收到 2 个对象 (cities2) 时,这适用于我的 RxJS 但由于我也可以接收 1 个对象,因此过滤器不是正确的做法
[问题] 如果只有一个对象存在,我应该首先检查城市流并添加另一个对象。或者什么是更好的 RxJS/逻辑选项?
const cities1 = [
{city: "LEUVEN",language: "nl"}
];
const cities2 = [
{city: "BRUSSEL",language: "nl"},{city: "BRUXELLES",language: "fr"}
];
const selectedLang = "fr"
const source$ = from(cities1);
const result = source$.pipe(
mergeMap((city) => {
return of(selectedLang).pipe(
map(lang => {
return {
lang: city.language,city: city.city,selectedLang: lang
}
}),filter(a => a.lang === selectedLang),pluck('city')
)
}
)
);
result.subscribe(console.log)
解决方法
如果 selectedLang 不是可观察的(即您不希望它改变),那么我认为如果您将其保留为值会更容易:
const result = source$.pipe(
filter(city => city.language === selectedLang)
map(city => city.city)
);
使用外部参数没有任何问题,它使流更易于阅读。
现在,如果 selectedLang 是一个 observable,并且您希望结果始终提供具有该 selectedLang 的城市,那么您可能需要合并两个流,同时保留到目前为止收到的所有城市:
const selectedLang$ = of(selectedLang); // This is actually a stream that can change value
const cities$ = source$.pipe(
scan((acc,city) => [...acc,city],[])
);
const result = combineLatest([selectedLang$,cities$]).pipe(
map(([selectedLang,cities]) => cities.find(city => city.language == selectedLang)),filter(found => Boolean(found))
map(city => city.city)
)
编辑:请注意,每次城市 $ 或 selectedLang$ 更改并且其中一个城市匹配时,都会发出此结果。如果您不想重复,则可以使用 distinctUntilChanged()
运算符 - 可能这可以使用排气映射或其他东西进行优化,但它会使 IMO 更难阅读。
感谢您的回复。这对我来说很有价值。事实上,我会忘记 selectedLang$ 并像常规字符串一样传递它。 问题 1 已解决
我会更详细地解释我的问题。我的 observable$ city$ 实际上是一个 GET 并且总是返回 1 或 2 两行。
leuven:
[ { city: 'LEUVEN',language: 'nl',selectedLanguage: 'fr' } ]
brussel:
[
{ city: 'BRUSSEL',selectedLanguage: 'fr' },{ city: 'BRUXELLES',language: 'fr',selectedLanguage: 'fr' }
]
如果它返回两行,我将能够过滤掉正确的值
filter(city => city.language === selectedLang) => BRUXELLES when selectedLangue is "fr"
但如果我只收到一行,我应该总是返回这个城市。
不使用 if 语句的最佳解决方案是什么?我一直在尝试使用对象析构和扫描数组,但结果始终是一个记录。
// HTTP get
const leuven: City[] = [ {city: "LEUVEN",language: "nl"} ];
// same HTTP get
const brussel: City[] = [ {city: "BRUSSEL",language: "nl"},{city: "BRUXELLES",language: "fr"}
];
mapp(of(brussel),"fr").subscribe(console.log);
function mapp(cities$: Observable<City[]>,selectedLanguage: string): Observable<any> {
return cities$.pipe(
map(cities => {
return cities.map(city => { return {...city,"selectedLanguage": selectedLanguage }}
)
}),// scan((acc,value) => [...acc,{ ...value,selectedLanguage} ])
)
}