Наблюдаемые объекты, сгруппированные в буфере

#reactive-programming #rxjs

#реактивное программирование #rxjs

Вопрос:

У меня есть следующий класс и массив

 class Hero {
    id: number;
    name: string;
}

const HEROES: Hero[] = [
    { id: 11, name: 'Narco' },
    { id: 12, name: 'Narco' },
    { id: 13, name: 'Bombasto' },
    { id: 14, name: 'Bombasto' },
    { id: 15, name: 'Bombasto' },
    { id: 16, name: 'Dynama' },
    { id: 17, name: 'Dynama' },
    { id: 18, name: 'Dynama' },
    { id: 19, name: 'Dynama' },
    { id: 20, name: 'Dynama' }
];
  

Я хочу создать наблюдаемый объект, который обрабатывает HEROES массив как источник, группирует массив по name и выдает результат в виде одного массива, т. Е. В итоге у меня должно получиться три массива: один для Narco , один для Bombasto и один для Dynama .

Я могу создать свой исходный наблюдаемый объект следующим образом

 var heroSource = Observable.create((observer:any) => {
            HEROES.forEach((hero: Hero) => {
                observer.next(hero);
            })
        });
  

Затем я могу сгруппировать героев, используя groupBy , т.е.,

 var groupHeroSource = heroSource
            .groupBy((hero: Hero) => {return hero.name});
  

Это фактически дает мне столько наблюдаемых, сколько разных имен в моем HEROES массиве (в данном случае три). Однако они будут выдаваться в виде последовательности, и в идеале я бы хотел, чтобы buffer они heroSource были завершены. Как бы я использовал buffer оператор в rxjs для моих сгруппированных наблюдаемых, чтобы создать единую коллекцию?

Ответ №1:

Прежде всего, вы можете создать свой первоначальный наблюдаемый объект намного проще:

 var heroSource = Observable.from(HEROES);
  

Далее, ваш картограф / селектор groupBy может быть сокращен до:

 var groupHeroSource = heroSource.groupBy((hero: Hero): string => hero.name);
  

Чтобы решить исходную проблему, мне нужно было буферизировать потоки, поскольку они готовы, буфер со временем 0 выполнит всю работу (я думаю, должно быть более элегантное решение), используйте take(1), чтобы получить только первый результат (и избежать повторяющегося буфера), а затемобъединить все:

 var finalGroup = groupHeroSource.map((ob) => ob.bufferWithTime(0).take(1)).mergeAll();
  

Обратите внимание, что поскольку ваш массив на самом деле статичен, передача его через поток и последующее его отображение могут быть не самым простым решением, вы можете просто уменьшить его:

 var grouped = HEROES.reduce((acc: any, hero: Hero) => {
  acc[hero.name] = acc[hero.name] || [];
  acc[hero.name].push(hero);
  return acc;
}, {});
  

Поскольку Object.values не является стандартным, вам придется перебирать ключи, чтобы получить массив, но, возможно, он лучше подходит для ваших нужд