I am trying to figure out how to get a grouped and aggregated array of values (that I can use with ngFor) starting from a list of objects, and for the life of me I can't make it work. The data (which is a slice of my state) looks something like this:
[{name: "A", value: 1, desc: 'something irrelevant'},
{name: "A", value: 3, desc: 'also other properties'},
{name: "B", value: 2, desc: 'etc.'},
{name: "B", value: 5, desc: 'etc.'}]
And the result I'm trying to get is something like (note that the type is different):
[{name: "A", value: 4}, {name: "B", value: 7}]
So, basically I want to find the distinct "names" and the sum of "value" for all the objects that have that name, with an output that can be used by ngFor | async.
My almost working solution to get the distinct values, at the moment, is:
this.aggregates:Observable<any[]> = this.store
.select(state => state.valuesList)
.map(valuesList => valuesList.sort((a,b) => {return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0);} }))
.flatMap(valuesList => valuesList)
.map(value => value.name)
.distinct();
I'd be happy to start with this; the problem is that, if I don't add a toArray(), Typescript complains about "Type string is not assignable to type any[]"; if I add toArray() after distinct(), it doesn't complain anymore but a subscribe() yields no result.
What am I doing wrong? Should I move everything to the reducer (but then I don't know if I can change the type of objects returned by different actions in the same reducer)? Any help is very very much appreciated.
UPDATE: I'd be even happier to have a working groupBy() implementation, since it should be exactly its use case.
You can use groupBy
to do what you want, but you have to use the groupBy
operator on an observable derived from the list - as groupBy
expects an observable of items.
In the following snippet, slice
is equivalent to this.store.select(state => state.valuesList)
const slice = Rx.Observable.of([
{ name: "A", value: 1, desc: "something irrelevant" },
{ name: "A", value: 3, desc: "also other properties" },
{ name: "B", value: 2, desc: "etc." },
{ name: "B", value: 5, desc: "etc." }
]);
const grouped = slice.concatMap(list => Rx.Observable
.from(list)
.groupBy(item => item.name)
.mergeMap(group => group
.reduce((total, item) => total + item.value, 0)
.map(total => ({ name: group.key, value: total }))
)
.toArray()
);
grouped.subscribe(value => console.log(value));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>