#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 не является стандартным, вам придется перебирать ключи, чтобы получить массив, но, возможно, он лучше подходит для ваших нужд