组合重叠的可观察流但采用最新值

时间:2015-01-05 16:22:03

标签: c# system.reactive

我有一个用例,我一直试图征服有关使用Rx组合流的问题。我有3个输出值的流:

S1: ----1----2----3----4----5-----6
S2: ----a---------c---------d------
S3: ---------x---------y----------z

我想结合(zip)流1和1 2和1& 3,逻辑是2& 3永远不能同时输出一个值。

所以期望的输出是:

1,a
2,x
3,c
4,y
5,d
6,z

但实际发生的是:

1,a
1,x
2,c
2,y
3,d
3,z

关于我如何获得所需输出的任何线索?

代码:

Subject<int> s1 = new Subject<int>();
Subject<string> s2 = new Subject<string>();
Subject<string> s3 = new Subject<string>();

var zip1 = s1.Zip(s2, (x, y) => {
    return new Tuple<int, string>(x, y);
});

var zip2 = s1.Zip(s3, (x, y) => {
    return new Tuple<int, string>(x, y);
});

zip1.Subscribe(Console.WriteLine, () => Console.WriteLine("Completed"));
zip2.Subscribe(Console.WriteLine, () => Console.WriteLine("Completed"));

s1.OnNext(1);
s2.OnNext("a");

s1.OnNext(2);
s3.OnNext("x");

s1.OnNext(3);
s2.OnNext("c");

s1.OnNext(4);
s3.OnNext("y");

s1.OnNext(5);
s2.OnNext("d");

s1.OnNext(6);
s3.OnNext("z");

2 个答案:

答案 0 :(得分:1)

对于您拥有的每个流,s2和s3,您可以创建Subject,订阅原始流,然后在等待下一个流后将值传递给新的Subject价值s1

var zip1 = new Subject<Tuple<int, string>>();
s2.Subscribe(async value =>
{
    var other = await s1.FirstAsync();
    zip1.OnNext(Tuple.Create(other, value));
});

var zip2 = new Subject<Tuple<int, string>>();
s3.Subscribe(async value =>
{
    var other = await s1.FirstAsync();
    zip2.OnNext(Tuple.Create(other, value));
});

您已声明您将管理流的时间,以便为其他流组合的每个值从s1产生一个值。如果你做到了,那你就没事了。如果在s1中产生多个值而在另一个流中没有任何相应的值,则忽略它,如果从s1中没有相应值的其他流中产生多个值,则将重复s1中产生的下一个值。

还有另一种选择更加人为,但在价值观之间的时间更灵活。这种方法首先将每个流投影到保存值的东西,但是将其与其他流区分开来。然后可以合并流,使用s1压缩流,然后可以创建多个流,过滤掉每个特定流的值。然后需要将它们投射回原始值。

var zip = s2.Select(s => Tuple.Create(1, s))
    .Merge(s3.Select(s => Tuple.Create(2, s)))
    .Zip(s1, Tuple.Create);

var zip1 = zip.Where(pair => pair.Item1.Item1 == 1)
    .Select(pair => Tuple.Create(pair.Item2, pair.Item1.Item2));
var zip2 = zip.Where(pair => pair.Item1.Item1 == 2)
    .Select(pair => Tuple.Create(pair.Item2, pair.Item1.Item2));

如果您实际上不需要单独的流,并且只想将输出复制为单个流,那么它实际上很多更简单:

var output = s1.Zip(s2.Merge(s3), Tuple.Create);
output.Subscribe(Console.WriteLine, () => Console.WriteLine("Completed"));

答案 1 :(得分:1)

这不仅仅是这样做吗?

var query =
    s1.Zip(s2.Merge(s3),
        (x, y) => new Tuple<int, string>(x, y));

根据问题中提供的代码,我得到了这个结果:

results