RxJs中的GroupBy和Sum

时间:2015-10-22 05:20:53

标签: javascript rxjs

我无法使用Lodash轻松解决一件我可以做的事情。 我需要groupBysum这样的东西,只使用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

2 个答案:

答案 0 :(得分:4)

我现在无法想办法用rx优雅地解决它 - 使用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') }
}

使用lodash

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

console.log('lodash:', v)

仅使用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));

如果您使用q代替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));

使用rx& lodash

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

答案 1 :(得分:1)

以下代码似乎适用于您的问题。

  • 关键部分是从groupBy observables获取一个数组。一旦掌握了数组,就可以将所需的聚合函数应用于您选择的库。
  • 请注意,这只适用于生成有限值序列的源,因为toArray函数将在释放数组之前等待源完成。
  • 还要注意,如果从数组创建observable,则大部分时间都会处理冷可观察对象,因此如果多次订阅,则会重放这些数组中出现的值。这可能是也可能不是想要的行为。请记住这一点。
  • 请注意以下代码中flatMap的使用。 groupBy发出流(每个组一个流),使用toArray允许您在一个数组中聚合每个流(组)的内容。 toArray运算符返回一个observable,其唯一值是统一数组。如果您使用map运算符而不是flatMap,则会发出一个observable而不是该observable发出的值。

代码在这里:

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在这里:http://jsbin.com/huqafajudi/edit?html,js,console

控制台输出:

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