如何将RxPY(或RxJS)combine_latest与group_by observable一起使用

时间:2017-10-22 21:59:40

标签: rxjs rxjs5 reactivex rx-py

在ReactiveX中,我可以从多个可观察量中的每一个中取出最新值,每个可观察量可能会或可能不会以不同的频率发射,如下所示(使用RxPY):

from __future__ import print_function

from rx import Observable
import time
import IPython
import random

random.seed(123)

x1 = Observable.interval(random.randint(50, 500))
x2 = Observable.interval(random.randint(50, 500))
x3 = Observable.interval(random.randint(50, 500))

xc = Observable.combine_latest(x1, x2, x3, lambda a1, a2, a3: [a1, a2, a3])

xc.subscribe(lambda s: print(s))

input("Press Enter to end")

然而,当使用group_by创建所述可观察对象时,我将如何做同样的事情,即,当任何一个observable发出一个值时,从每组observable中打印最新值?

from __future__ import print_function

from rx import Observable
import time
import IPython
import random

random.seed(123)

n = 5
xx = Observable.interval(random.randint(50, 500)).group_by(lambda x: x % 5) # create n observables
print(xx)

这就是返回一个可观察的组对象:

<rx.core.anonymousobservable.AnonymousObservable object at 0xb631bb10>

因此,对于任何给定的n ,我将如何对此对象执行相同的combine_latest操作?

我知道在这个程式化的例子中,观察者会以相同的速率发射,但我需要根据顶部的显式例子将解决方案推广到不同的发射频率。

鉴于RxPY和RxJS的结构非常相似,我很乐意考虑类似的RxJS答案。

1 个答案:

答案 0 :(得分:1)

编辑:如果群组的数量是有限的且非常小,这是一种更简洁的方式,您可以在不牺牲性能的情况下实现这一目标:

groups$.scan(lambda prev, group$: [
               Observable.combineLatest(prev + [group$])\
                         .map(lambda nest: nest[0] + [nest[1]] if len(nest) == 2 else nest)
             ], [])

在这里,scan构建一个Observable,它可以在任何组发出的任何时候发出。它通过嵌套上一次迭代中的组列表中的排放来实现此目的。因为prev是一个可观察的数组,所以我们使用map使用list concat进行展平。包裹scan结果的数组适应第一组的基本情况。

编辑:我在写下答案之后意识到一点,它的行为在所有流再发出一个之前不会发出任何项目,是可能不想要。在我的头脑中,最短但当然不是最干净的解决方案是隐藏最新的值并用它们启动每个流,如下所示:

def group_combine(groups$):
  last = []

  def mutate_last(v): # too bad this isn't JS :/
    last = v

  return groups$.scan(lambda streams, next_stream: streams + [next_stream], [])\
                .switch_map(lambda streams: Observable.combine_latest(
                  [stream.start_with(last[i]) if i < len(last) else stream\
                     for i, stream in enumerate(streams)]
                ))\
                .for_each(mutate_last)

尝试一下:

// groups$ = x.group_by(...)
groups$.scan(lambda streams, next_stream: streams + [next_stream], [])\
       .switch_map(lambda streams: Observable.combine_latest(streams))\
       .subscribe(lambda values: ...)

首先,我们将群组流累积到不断增长的列表中,然后我们继续切换到该列表上的combine_latest