Rx通过加入一个属性来组合许多流

时间:2016-05-17 10:07:06

标签: c# system.reactive reactive-programming

我正在尝试拉链' Rx中的任意数量的流,其中元素对应但可以不按顺序处理。每个流的元素都有一个标识符,可用于将它们匹配在一起。例如。元素看起来像:

public class Element
{
    public string Key {get; set;}
}

通常,zip只会根据其出现次数组合元素:

|-A-----------A
|--B---------B-
|-----C------C-
|-----ABC-----ABC  <- zip

但是,如果我们只想匹配共享相同Key的元素呢?我正在寻找一个更像这样的序列:

(在此示例中,键为1或2)

|--2A-------1A----------
|----1B----------2B-----
|------1C-----------2C--
|-----------1ABC----2ABC   <- zipped by key 1 & 2 respectively

我觉得GroupJoin适合这种情况,但它只服务于两个Observable并且链接它们很快失控。

我也看了And / Then / When但是并没有真正理解如何为这种情况构建它。

理想情况下,我想要一个我可以调用并提供结果选择器的扩展方法,其中结果选择器的输入保证具有相同的键。

你会如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

这是我在LinqPad中碰到的东西。它符合您对大理石图的要求。然而,它比我想要的更加混乱。

Nuget依赖Rx-Testing

void Main()
{
    TestScheduler scheduler = new TestScheduler();
    /*
|--2A-------1A----------
|----1B----------2B-----
|------1C-----------2C--
|-----------1ABC----2ABC   <- zipped by key 1 & 2 respectively

    */
    var sourceA = scheduler.CreateColdObservable(
        ReactiveTest.OnNext(3, "2A"),
        ReactiveTest.OnNext(12, "1A"));
    var sourceB = scheduler.CreateColdObservable(
        ReactiveTest.OnNext(5, "1B"),
        ReactiveTest.OnNext(17, "2B"));
    var sourceC= scheduler.CreateColdObservable(
        ReactiveTest.OnNext(7, "1C"),
        ReactiveTest.OnNext(20, "2C"));

    var observer = scheduler.CreateObserver<string>();


    var query = Observable.Merge(sourceA, sourceB, sourceC)
        .GroupBy(x => GetKey(x))
        .SelectMany(grp => grp.Select(x=>GetValue(x))
                              .Take(3)
                              .Aggregate(new List<string>(), 
                                        (accumulator, current) => { 
                                            accumulator.Add(current); 
                                            return accumulator;
                                        })
                            .Select(acc=>CreateGroupResult(grp.Key, acc)));

    query.Subscribe(observer);
    scheduler.Start();

    ReactiveAssert.AreElementsEqual(
        new[]{
            ReactiveTest.OnNext(12, "1ABC"),
            ReactiveTest.OnNext(20, "2ABC")
        },
        observer.Messages
    );

}

// Define other methods and classes here
private static string CreateGroupResult(string key, IEnumerable<string> values)
{
    var combinedOrderedValues = string.Join(string.Empty, values.OrderBy(v => v));
    return string.Format("{0}{1}", key, combinedOrderedValues);
}

private static string GetKey(string message)
{
    return message.Substring(0, 1);
}

private static string GetValue(string message)
{
    return message.Substring(1);
}