【问题标题】:Merge two Observables into one Observable of the same type将两个 Observable 合并为一个相同类型的 Observable
【发布时间】:2021-02-12 00:58:25
【问题描述】:

我有两个相同类型的 Observable,我想合并为一个 Observable 并删除重复项。

到目前为止,我基本上尝试了所有 rxjs 运算符,但没有一个能满足我的需要。见附图:很多 rxjs 操作符改变了结果 observable 的类型。

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

这是我检索一些数据的两个调用。

现在最接近的两个操作:

combineLatest(a, b);

这个用两个索引创建了一个新数组,a 的结果将进入索引 0,b 的结果将进入索引 1。我不能这样使用它。

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

这个差点搞定了。这里的问题如下: 让我们假设 a 返回 2 个结果(示例值:1 和 2)并且 b 也返回 2 个结果(示例值:2 和 3)。所以“2”是重复的,它不应该在结果 observable 中出现两次。

有谁知道运算符的组合,以便我可以组合两个可观察对象并删除重复项?

【问题讨论】:

    标签: javascript angular


    【解决方案1】:

    由于您的 observables 是 http 调用,我假设它们在发出后完成。你可以使用 forkJoin 来组合它们:

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

    如果你的 observables 没有完成,使用 combineLatest:

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

    【讨论】:

      【解决方案2】:

      如果你的 Observables 不是 hot,例如。他们不会推送多个值,并且会发出一个数组并完成,这应该可以:

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

      【讨论】:

        【解决方案3】:

        这取决于您的确切需求。例如,如果您仅指连续重复(即“AAA”应该变为“A”,但“ABA”很好),则删除重复项会更容易。如果您只想要 唯一值,我认为您需要 scan 和一些重复数据删除逻辑。它们发出的是对象还是原语?

        在最简单的情况下,这样做:

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

        或者,删除所有重复项:

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

        (对象会变得有点棘手)。

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

        【讨论】:

          【解决方案4】:

          使用 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 示例:https://stackblitz.com/edit/ued3me?file=index.ts

          【讨论】:

            猜你喜欢
            • 2019-06-06
            • 1970-01-01
            • 2017-08-04
            • 2011-10-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多