解决过滤器/合并问题的 RxJS 逻辑

问题描述

我想这更像是一个逻辑问题,而不是 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} ])
    )
}