最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - GroupBy and Sum in RxJs - Stack Overflow

programmeradmin1浏览0评论

I can't get my head around a thing that I could do with ease using Lodash. I need to groupBy and sum, something like this, only using RxJs:

let arr = [
        {n: 'a', q: 1 }, 
        {n: 'a', q: 2}, 
        {n: 'b', q: 4 }
];

let v = _(arr).chain().groupBy('n').map(sumQt).value()

function sumQt(x) {
   return { name: x[0].n, qt: _.sum(x, 'q') }
}

// it produces array like: [{ name: "a", qt: 3 }, { name: "b", qt: 4 }]

jsbin here

I can't get my head around a thing that I could do with ease using Lodash. I need to groupBy and sum, something like this, only using RxJs:

let arr = [
        {n: 'a', q: 1 }, 
        {n: 'a', q: 2}, 
        {n: 'b', q: 4 }
];

let v = _(arr).chain().groupBy('n').map(sumQt).value()

function sumQt(x) {
   return { name: x[0].n, qt: _.sum(x, 'q') }
}

// it produces array like: [{ name: "a", qt: 3 }, { name: "b", qt: 4 }]

jsbin here

Share Improve this question asked Oct 22, 2015 at 5:20 iLemmingiLemming 36.3k61 gold badges198 silver badges316 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

I can't think of any way to solve it elegantly using just rx right now - is using rx + lodash ok?

jsbin

// setup
let arr = [{n: 'a', q: 1 }, 
           {n: 'a', q: 2}, 
           {n: 'b', q: 3 }];

function sumQt(x) {
  return { name: x[0].n, qt: _.sum(x, 'q') }
}

using lodash

let v = _(arr)
.chain()
.groupBy('n')
.map(sumQt)
.value()

console.log('lodash:', v)

using just rx

Rx.Observable.from(arr)
  .groupBy(x => x.n)
  .flatMap(group => {
    return group.reduce((acc, currentValue) => {
      acc.n = currentValue.n;
      acc.qt = acc.qt + currentValue.q;
      return acc;
    }, {n: undefined, qt: 0})
  })
  .subscribe(sum => console.log('rx:', sum));

which would be prettier if you were fine with using q instead of qt

Rx.Observable.from(arr)
  .groupBy(x => x.n)
  .flatMap(group => {
    return group.reduce((acc, currentValue) => {
      acc.q = acc.q + currentValue.q;
      return acc;
    })
  })
  .subscribe(sum => console.log('rx:', sum));

using rx & lodash

Rx.Observable.from(arr)
  .groupBy(x => x.n)
  .flatMap(group => group.toArray())
  .map(sumQt)
  .subscribe(sum => console.log('rx+lodash:', sum));

The code below seems to be working for your issue.

  • The key part is getting an array back from the groupBy observables. Once you have an array in your hand, you can apply whatever aggregation function you want with the library of your choice.
  • Note that this will only work with a source which generate a finite sequence of values, as the toArray function will wait for the source to be pleted before releasing the array.
  • Be also careful that if you create observable from arrays, you will be handling most of the time cold observables, so if you subscribe to those several times, you will replay the values ing out of those arrays. This might or might not be the wanted behaviour. Just keep it in mind.
  • Note the use of the flatMap in the code below. groupBy emits streams (one stream for each group), using toArray allows you to aggreate the content of each stream (group) in one array. The toArray operator returns an observable whose unique value is the consolidated array. If you would use the map operator instead of flatMap, you would emit an observable instead of the values emitted by that observable.

Code here:

var arr = [{n : 'a', q : 1},
           {n : 'a', q : 4},
           {n : 'b', q : 4}];
var key_group_by = 'n';
var key_sum_by = 'q';

var groupedArr$ = Rx.Observable.from(arr)
    .groupBy(function ( x ) {
               return x[key_group_by];
             })
    .flatMap(function ( groupedKeys$ ) {
               // groupKeys$ is an observable
               return groupedKeys$
                   .toArray()
                   .map(sum_by(key_sum_by));
             });

function sum_by ( key ) {
  return function sum_by_key ( aHashMap ) {
    var result = {};
    // Here you could also use your underscore library
    var acc = 0;
    aHashMap.forEach(function ( value ) {acc += value[key];});
    aHashMap[0][key] = acc;
    return aHashMap[0];
  };
}

groupedArr$.subscribe(emits("groups:"));

function emits ( who ) {
  return function ( x ) { console.log([who, "emits"].join(" "), x);};
}

jsbin here : http://jsbin./huqafajudi/edit?html,js,console

console output:

"groups: emits"
[object Object] {
  n: "a",
  q: 5
}
"groups: emits"
[object Object] {
  n: "b",
  q: 4
}
发布评论

评论列表(0)

  1. 暂无评论