【问题标题】:How do you group a stream, then process groups separately based on the group's key?您如何对流进行分组,然后根据组的键分别处理组?
【发布时间】:2017-01-28 18:35:03
【问题描述】:

首先,我对流还很陌生,所以我仍在掌握一些常见的模式。

在许多库中,我们可以使用 .groupBy(keySelectorFn) 将流拆分为流。例如,此流根据每个对象中 'a' 的值拆分为流(伪代码,不基于任何特定库):

var groups = Stream.of(
    { a: 1, b: 0 },
    { a: 1, b: 1 },
    { a: 2, b: 2 },
    { a: 1, b: 3 }
)
.groupBy(get('a'));

假设我想根据该组的 'a' 的值来不同地处理组:

groups.map(function(group) {
    if (..?) {
        // Run the group through some process
    }

    return group;
});

如果不消耗每个组的第一个元素,我看不到如何获取“a”的值(如果消耗了组的第一个元素,则该组不再完整)。

在我看来,这似乎是我想用流做的一件相当普遍的事情。我是否采取了错误的方法?

--- 编辑 ---

以下是我遇到的问题的更具体示例:

var groups = Stream.of(
    { a: 1, b: 0 },
    { a: 1, b: 1 },
    { a: 2, b: 0 },
    { a: 2, b: 1 },
    { a: 2, b: 2 },
    { a: 1, b: 2 }
)
.groupBy(get('a'));

如何选择 a === 1 的前 1 个对象和 a === 2 的前 2 个对象,并直接传递任何其他对象?这在我看来是合乎逻辑的:

groups.chain(function(group) {
    return group.key === 1 ?
        group.take(1) :
    group.key === 2 ?
        group.take(2) :
        group ;
});

但是 group.key 不存在(即使它存在也会看起来有点……臭)。

【问题讨论】:

标签: javascript stream rxjs bacon.js ramda.js


【解决方案1】:

groupBy 将为您提供一个流(流中的每个值都是流本身)。使用折叠,您可以将每个组(这是一个流)处理成单个值(使用条件)。 flatMap 将所有结果放入一个流中。这是一个处理对象组的简单示例。它根据属性“a”对对象进行分组,根据值对包含 type 和 val 属性的单个对象进行算术运算。这些最终对象被扁平化为单个流:

var groupStream = Bacon.fromArray([ { a: 1, b: 0 }, { a: 1, b: 1 }, { a: 2, b: 2 }, { a: 1, b: 3 } ]); // -----[a=1 的对象流]--------[a=2 的对象流]----> var groups = groupStream.groupBy(function(k){ return k.a; }) // v 是 a=1 个对象或 a=2 个对象的流 groups.flatMap(function(v) { //折叠(减少)v(流)中的值 return v.fold({type:'', val: 0},function(acc,i) { 如果(i.a == 1){ 返回{类型:'一个',val:acc.val + i.b}; } 如果(i.a == 2){ 返回{类型:'两个',val:acc.val + i.b}; } }) }).onValue(函数(v) { 控制台.log(v); });

这里是 jsbin:http://jsbin.com/haliqerita/edit?js,console

希望对您有所帮助。

【讨论】:

  • 好的,好的。我可以看到使用 .fold()(或 .reduce())可能是前进的方向。但是您对 .fold() 中的属性“a”进行了条件检查...看到您已经按“a”的值对 groupStream 进行了分组,因此必须检查这些组中的每个对象的值似乎有点浪费的'一个'。人们吹嘘流的一件事是它们的效率。诚然,一张小小的支票并不是什么大问题,但我对这种事情感到惊讶。
  • 现在想象一下,我想取 a === 1 的前 1 个对象,但 a === 2 的前 2 个对象。.fold() 在这里并没有真正的帮助,除非我在 .flatMap 中放置一些可递增的计数器变量——实际上,我需要为每个“a”值一个计数器变量(我可能不知道有多少个“a”值)。理想情况下,我想做 if (v.key === 1) { return v.take(1); } if (v.key === 2) { return v.take(2); } ...但没有像 v.key 这样的东西 ...
  • 我在问题中添加了一个示例来说明该问题。
猜你喜欢
  • 2017-05-17
  • 2023-03-24
  • 2012-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-21
  • 1970-01-01
相关资源
最近更新 更多