简体   繁体   English

将两个 Observable 合并为一个相同类型的 Observable

[英]Merge two Observables into one Observable of the same type

I have two Observables of the same type that I want to merge into one observable and remove duplicates.我有两个相同类型的 Observable,我想将它们合并为一个 observable 并删除重复项。

By now I tried basically all rxjs operators but none of them do what I need.到目前为止,我基本上尝试了所有 rxjs 运算符,但没有一个能满足我的需要。 See the attached picture: a lot of the rxjs operators change the type of the resulting observable.见附图:很多 rxjs 操作符改变了结果 observable 的类型。 在此处输入图像描述

const a: Observable<Foo[]> = ...
const b: Observable<Foo[]> = ...

These are my two calls to retrieve some data.这是我检索一些数据的两个调用。

Now the two operations that came the closest:现在最接近的两个操作:

combineLatest(a, b);

This one makes a new array with two indexes and the results of a will go in index 0 and results of b will go into index 1. I cant use it like this.这个创建了一个具有两个索引的新数组,a 的结果将 go 放入索引 0,b 的结果将 go 放入索引 1。我不能这样使用它。

const c = a.pipe(mergeMap(a1 => b.pipe(map(a2 => [...a1, ...a2]))));

This one nearly got it.这个差一点就明白了。 The problem here is following: Lets assume a return 2 results (example value: 1 and 2) and b return also 2 results (example value: 2 and 3).这里的问题如下:假设 a 返回 2 个结果(示例值:1 和 2)并且 b 也返回 2 个结果(示例值:2 和 3)。 So the "2" is a duplicate, which should not appear twice in the resulting observable.所以“2”是重复的,它不应该出现在结果 observable 中两次。

Does anyone know a combination of the operators so I can combine both observables and remove the duplicates?有谁知道运算符的组合,以便我可以组合两个可观察对象并删除重复项?

If your Observables are not hot , eg.如果您的 Observables 不,例如。 they will not push multiple values and will emit one array and complete, this should work:他们不会推送多个值,并且会发出一个数组并完成,这应该可以:

combineLatest(a, b).pipe(
  map(([a, b]) => {
    const filtered = a.filter(i => !b.includes(i));
    return [...filtered, b];
  })
)

Since your observables are http calls, I assume they complete after emitting.由于您的 observables 是 http 调用,我假设它们在发射后完成。 you can use forkJoin to combine them:你可以使用 forkJoin 来组合它们:

const combine= forkJoin(a, b).pipe(
    map(([a, b]) => a.concat(b))
);

if your observables do not complete, use combineLatest:如果您的 observables 没有完成,请使用 combineLatest:

const combine= combineLatest(a, b).pipe(
    map(([a, b]) => a.concat(b))
);

It depends on your exact needs.这取决于您的确切需求。 For example, removing duplicates is way easier if you only mean sequential duplicates (ie "AAA" should become "A", but "ABA" is fine).例如,如果您只表示顺序重复(即“AAA”应该变为“A”,但“ABA”很好),则删除重复项会更容易。 If you want only unique values, I think you need scan with some deduplicating logic.如果您只想要唯一值,我认为您需要使用一些重复数据删除逻辑进行scan And are they emitting objects, or primitives?它们发出的是对象还是原语?

In the simplest case, this will do:在最简单的情况下,这样做可以:

merge(a, b).pipe(distinctUntilChanged())

Or, with removing all duplicates:或者,删除所有重复项:

const deduplicate = arr => [...new Set(arr)];

merge(a, b).pipe(scan(
  (acc, curr) => deduplicate([...acc, curr]), []
)).subscribe(/* ... */);

(It'll get a little trickier with objects). (对象会变得有点棘手)。

Here's a stackblitz: https://stackblitz.com/edit/typescript-a97ag7?file=index.ts&devtoolsheight=100这是一个堆栈闪电战: https://stackblitz.com/edit/typescript-a97ag7?file=index.ts&devtoolsheight=100

Use zip to achieve this.使用zip来实现这一点。

import { zip } from 'rxjs';

let age$ = of<number>(27, 25, 29);
let name$ = of<string>('Foo', 'Bar', 'Beer');
let isDev$ = of<boolean>(true, true, false);

zip(age$, name$, isDev$).pipe(
  map(([age, name, isDev]) => ({ age, name, isDev })),
)
.subscribe(x => console.log(x));

stackblitz example: https://stackblitz.com/edit/ued3me?file=index.ts stackblitz示例: https://stackblitz.com/edit/ued3me?file=index.ts

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM