RxJS фильтр () оператор

Я пытаюсь найти самое чистое решение для использования filter() оператор для того, чтобы отфильтровать мои наблюдаемые.

Здесь я повторяю вызов службы, чтобы получить femaleList по отдельности

export class MyComp implements OnInit {

    maleList: IContact[] = [];
    femaleList: IContact[] = [];    

    constructor(private _contactService: ContactService) { }
    ngOnInit() : void {
        this._contactService.getContacts()
         .filter(male => male.gender === 'M')
        subscribe(maleList => this.maleList = maleList);

        this._contactService.getContacts()
         .filter(female => female.gender === 'F')
        subscribe(femaleList => this.femaleList = femaleList);
     } }

Список контактов

 [{
      "id" : 1,
      "name" : "Todd",
      "gender" : "M"
    }, {
      "id" : 2,
      "name" : "Lillian",
      "gender" : "F"
    }]

Есть ли какая-либо опция в операторах RxJS с одной наблюдаемой для назначения двум переменным.

Как я могу отфильтровать контакты и назначить их maleList а также femaleList используя RxJS filter() оператор.

заранее спасибо

3 ответа

Решение

Вам не нужен фильтр:

this._contactService.getContacts()
  .subscribe(person => {
    if(person.gender === 'F'){
      this.femaleList.push(person);
    } else {
      this.maleList.push(person);
    }

Если вы хотите использовать один Observable и подписаться на него с двумя разными Observer, вам нужно будет использовать share() или же shareReplay() (который в RxJS 5 теперь доступен только с .publishReplay().refCount()) (См. https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/publish.md и https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/sharereplay.md).

let data = [{
    "id" : 1,
    "name" : "Todd",
    "gender" : "M"
}, {
    "id" : 2,
    "name" : "Lillian",
    "gender" : "F"
}];

let maleList = [];
let femaleList = [];

let source = Observable.defer(() => {
        console.log('Observable.defer');
        return Observable.from(data);
    })
    .publishReplay()
    .refCount();

source
    .filter(male => male.gender === 'M')
    .toArray()
    .subscribe(list => maleList = list);

source
    .filter(male => male.gender === 'F')
    .toArray()
    .subscribe(list => femaleList = list);

console.log('maleList', maleList);
console.log('femaleList', femaleList);

Смотрите живую демонстрацию: https://jsbin.com/hapofu/edit?js,console

Это выводит на консоль:

Observable.defer
maleList [ { id: 1, name: 'Todd', gender: 'M' } ]
femaleList [ { id: 2, name: 'Lillian', gender: 'F' } ]

Оба эти подписчика имеют одно и то же соединение с source и в то же время ответ "воспроизводится" (если вы подпишетесь после того, как он был впервые отправлен, он будет переслан без подписки на source снова).

Обратите внимание, что предметы из filter() испускаются по одному за раз. Вот почему я использовал toArray() собрать все значения и переслать их в виде одного массива. В качестве альтернативы я мог бы позвонить, например. maleList.push() с каждым значением.

Кстати, есть также partition() оператор, который вы могли бы использовать вместо filter() чтобы избежать создания двух подписок.

Вы можете использовать lodash:

.partition (коллекция, [предикат =.identity]);

https://lodash.com/docs/

Это возвращает 2 массива, один, где значения оцениваются как false, а другой - как true. Просто используйте "пол", чтобы построить оценку.

Другие вопросы по тегам