【问题标题】:RxJs merging two observables uniquelyRxJs 独特地合并两个可观察对象
【发布时间】:2020-09-22 06:09:40
【问题描述】:

我正在使用 rxjs 在 Angular App 中构建搜索和过滤系统。

我有以下几点:

interface User{ //exmaple model
 _id: string;
 name: string;
}

filters$ = new BehaviorSubject<Array<User>>([]);
search$ = new BehaviorSubject<Array<User>>([]);

// I use these two and merge them in another function as following

const myData$ = merge(this.search$.asObservable(), this.filters$.asObservable())
.pipe(distinctUntilChanged(distinctCheck))

使用实用函数distinctCheck 类似于:

const distinctKey = (elem) => {
    if(elem === null){
      return elem
    }
    if(this.hasId(elem)){
      return elem["_id"];
    }
    if(this.hasName(elem)){
      return elem["name"]
    }
    return this.createComparisonString(elem)
  }

但这对我来说要么是一个可观察的,要么是另一个。所以我的问题是:

如何合并两个 observables 并只发出两个数组共有的值?有时 filters$ 可能会发出一个包含 30 个元素的数组。有时 search$ 可能会发出一个只有 2 个元素的数组?

IE:

如果filter$ 包含:

[{_id:'1', name:'jhon'},{_id:'2', name:'doe'},{_id:'3', name:'jolly'},{_id:'4', name:'some random dude'},{_id:'5', name:'some random other dude'},{_id:'6', name:'johny'},{_id:'7', name:'bravo'}]

search$ 包含:

[{_id:'1', name:'jhon'},{_id:'101', name:'myDoe'},{_id:'301', name:'some-jolly'},{_id:'4', name:'some random dude'}, {_id:'7', name:'bravo'}]

我希望myData$ 发出类似:

[{_id:'1', name:'jhon'},{_id:'4', name:'some random dude'}, {_id:'7', name:'bravo'}]

谢谢大家! :)

【问题讨论】:

    标签: angular typescript rxjs rxjs6


    【解决方案1】:

    您实际上可以使用纯 Javascript 实现它。

    var filterArr = [{_id:'1', name:'jhon'},{_id:'2', name:'doe'},{_id:'3', name:'jolly'},{_id:'4', name:'some random dude'},{_id:'5', name:'some random other dude'},{_id:'6', name:'johny'},{_id:'7', name:'bravo'}]
    var searchArr = [{_id:'1', name:'jhon'},{_id:'101', name:'myDoe'},{_id:'301', name:'some-jolly'},{_id:'4', name:'some random dude'}, {_id:'7', name:'bravo'}]
    
    var data = filterArr.filter(userFilter => searchArr.some(userSearch => userFilter._id == userSearch._id))
    
    console.log(data);

    对于 observables,您可以尝试使用combineLatest 方法将它们组合起来。

    const myData$ = combineLatest(this.search$.asObservable(), this.filters$.asObservable()).pipe(
      map(([filterArr, searcheArr]) => filterArr.filter(userFilter => searchArr.some(userSearch => userFilter._id == userSearch._id)))
    )
    

    【讨论】:

      【解决方案2】:

      distinctUntilChanged 运算符的compare 函数用于判断之前的发射是否与当前的发射不同。

      据我了解您的问题,您正在寻找 searchfilter 数组之间的交集。

      首先,使用combineLatest 运算符在search$ of filter$ 发出时得到通知。
      然后,您可以使用类似 lodash 的 intersectionWith 来获取数组交集。

      您的代码应如下所示:

      const comperator = (search, filter) => filter._id === search._id && filter.name === search.name; 
      
      const myData$ = combineLatest(search$, filter$).pipe(
        map(([search, filter]) => intersectionWith(search, filter, comperator))
      );
      

      你可以在this stackblitz查看完整的运行代码

      【讨论】:

        【解决方案3】:

        这样的事情应该可以工作:

        const filters$ = new BehaviorSubject<Array<{ id: string }>>([]);
        const search$ = new BehaviorSubject<Array<{ id: string }>>([]);
        
        const combinedAndFiltered$ = combineLatest(filters$, search$)
            .pipe(map(([filters, searches]) => {
                return filters.filter(filter => !!searches.find(search => search.id === filter.id));
            }));
        
        combinedAndFiltered$.subscribe(console.log)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-01-25
          • 2016-06-18
          • 2019-10-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多