将一个可观察量与另一个可观察量的最新值相结合

时间:2014-12-16 14:58:13

标签: c# system.reactive

我正在尝试组合两个值,它们的值共享一些密钥。

每当第一个observable产生一个新值时,我想产生一个新值,并结合第二个observable的最新值,该值取决于第一个observable的最新值。

伪代码示例:

var obs1 = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => Tuple.create(SomeKeyThatVaries, x)

var obs2 = Observable.Interval(TimeSpan.FromMilliSeconds(1)).Select(x => Tuple.create(SomeKeyThatVaries, x)

from x in obs1
  let latestFromObs2WhereKeyMatches = …
  select Tuple.create(x, latestFromObs2WhereKeyMatches)

有什么建议吗?

显然,这可以通过订阅第二个observable并创建一个具有可由键索引的最新值的字典来实现。但我正在寻找一种不同的方法..

使用场景:从股票报价流计算的一分钟价格条。在这种情况下,关键是自动收报机,字典包含具体代码的最新询价和出价,然后在计算中使用。

(顺便说一下,谢谢戴夫和詹姆斯,这是一次非常富有成效的讨论)

(抱歉格式化,很难在iPad上找到它......)

2 个答案:

答案 0 :(得分:2)

...你为什么要寻找不同的方法?听起来你对我来说是对的。这是简短的代码...粗略地说它会是这样的:

var cache = new ConcurrentDictionary<long, long>();    
obs2.Subscribe(x => cache[x.Item1] = x.Item2);    
var results = obs1.Select(x => new {
    obs1 = x.Item2,
    cache.ContainsKey(x.Item1) ? cache[x.Item1] : 0
});

在一天结束时,C#是一种OO语言,线程安全的可变集合的繁重工作已经完成了。

可能有花哨的Rx方法(感觉可能会涉及到连接)......但它的可维护性如何?它将如何表现?

$ 0.02

答案 1 :(得分:2)

我想知道这样一个查询的目的。你介意稍微描述使用场景吗?

尽管如此,以下查询似乎可以解决您的问题。如果您已经有某种方法来识别每个值的来源,那么初始预测就不是必需的,但为了概括起见,我将它们包括在内,以便与您极其抽象的提问模式保持一致。 ; - )

注意:我假设someKeyThatVaries不是您显示的共享数据,这就是为什么我还包含了anotherKeyThatVaries这个词;否则,整个查询对我来说毫无意义。

var obs1 = Observable.Interval(TimeSpan.FromSeconds(1))
                     .Select(x => Tuple.Create(someKeyThatVaries, x));
var obs2 = Observable.Interval(TimeSpan.FromSeconds(.25))
                     .Select(x => Tuple.Create(anotherKeyThatVaries, x));

var results = obs1.Select(t => new { Key = t.Item1, Value = t.Item2, Kind = 1 })
                  .Merge(
              obs2.Select(t => new { Key = t.Item1, Value = t.Item2, Kind = 2 }))
                  .GroupBy(t => t.Key, t => new { t.Value, t.Kind })
                  .SelectMany(g =>
                    g.Scan(
                      new { X = -1L, Y = -1L, Yield = false },
                      (acc, cur) => cur.Kind == 1
                                  ? new { X = cur.Value, Y = acc.Y, Yield = true }
                                  : new { X = acc.X, Y = cur.Value, Yield = false })
                      .Where(s => s.Yield)
                      .Select(s => Tuple.Create(s.X, s.Y)));