Reputation: 9605
I have the following class and array
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' }
];
I want to create an observable that treats the HEROES
array as the source, groups the array by name
and emits the result as a single array, i.e., I should end up with three arrays, one for Narco
, one for Bombasto
and one for Dynama
.
I can create my source observable as follows
var heroSource = Observable.create((observer:any) => {
HEROES.forEach((hero: Hero) => {
observer.next(hero);
})
});
I can then group heros by using groupBy
, i.e.,
var groupHeroSource = heroSource
.groupBy((hero: Hero) => {return hero.name});
This effectively gives me as many observables as there are different names in my HEROES
array (three in this case). However, these will be emitted as a sequence and ideally I'd like to buffer
them until heroSource
is complete. How would I use the buffer
operator in rxjs on my grouped observables so that emit a single collection?
Upvotes: 0
Views: 404
Reputation: 14395
First of all you can create your initial observable much simpler:
var heroSource = Observable.from(HEROES);
Next, your groupBy mapper/selector can be abbreviated to:
var groupHeroSource = heroSource.groupBy((hero: Hero): string => hero.name);
To solve the original problem I needed to buffer the streams, since they are ready a buffer with time of 0 would do the work (I guess there should be a more elegant solution out there), use take(1) to take only the first result (and avoid a repeating buffer) and then merge all:
var finalGroup = groupHeroSource.map((ob) => ob.bufferWithTime(0).take(1)).mergeAll();
Note that since that since your array is actually static, putting it through a stream and then mapping it might not be the simplest solution, you can simply reduce it:
var grouped = HEROES.reduce((acc: any, hero: Hero) => {
acc[hero.name] = acc[hero.name] || [];
acc[hero.name].push(hero);
return acc;
}, {});
Since Object.values is not standard, you'll have to iterate the keys to get an array, yet, it might be a better fit for your need
Upvotes: 4