【问题标题】:Can I Pair Two Sequences Together by a Matching Key?我可以通过匹配键将两个序列配对在一起吗?
【发布时间】:2013-02-28 07:29:34
【问题描述】:

假设序列 1 正在网络上检索站点 1、2、3、4、5 的内容(但将以不可预测的顺序返回)。

序列 2 将进入数据库以检索关于这些相同记录 1、2、3、4、5 的上下文(但出于本示例的目的,将以不可预知的顺序返回)。

当每个匹配对在两个序列中都准备好时,是否有一种 Rx 扩展方法可以将它们组合成一个序列?即,如果第一个序列以 4,2,3,5,1 的顺序返回,而第二个序列以 1,4,3,2,5 的顺序返回,则合并后的序列将是 (4,4), (3 ,3), (2,2), (1,1), (5,5) - 一旦每对准备好。我查看了 Merge 和 Zip,但它们似乎并不是我想要的。

我不想丢弃不匹配的对,我认为这排除了简单的 .Where.Select 组合。

【问题讨论】:

    标签: system.reactive


    【解决方案1】:
    var paired = Observable
        .Merge(aSource, bSource)
        .GroupBy(i => i)
        .SelectMany(g => g.Buffer(2).Take(1));
    

    下面的测试给出了正确的结果。目前它只是采用整数,如果您使用带有键和值的数据,那么您需要按 i.Key 而不是 i 进行分组。

    var aSource = new Subject<int>();
    var bSource = new Subject<int>();
    
    paired.Subscribe(g => Console.WriteLine("{0}:{1}", g.ElementAt(0), g.ElementAt(1)));
    
    aSource.OnNext(4);
    bSource.OnNext(1);
    aSource.OnNext(2);
    bSource.OnNext(4);
    aSource.OnNext(3);
    bSource.OnNext(3);
    aSource.OnNext(5);
    bSource.OnNext(2);
    aSource.OnNext(1);
    bSource.OnNext(5);
    

    产量:

    4:4
    3:3
    2:2
    1:1
    5:5
    

    编辑以回应布兰登:

    对于项目为不同类(AClass和BClass)的情况,可以进行如下调整。

    using Pair = Tuple<AClass, BClass>;
    
    var paired = Observable
        .Merge(aSource.Select(a => new Pair(a, null)), bSource.Select(b => new Pair(null, b)))
        .GroupBy(p => p.Item1 != null ? p.Item1.Key : p.Item2.Key)
        .SelectMany(g => g.Buffer(2).Take(1))
        .Select(g => new Pair(
          g.ElementAt(0).Item1 ?? g.ElementAt(1).Item1, 
          g.ElementAt(0).Item2 ?? g.ElementAt(1).Item2));
    

    【讨论】:

    • 哇,太好了!非常感谢,我没有意识到我可以通过 Merge 在这里得到我需要的东西。我把它加到最后,这样最终的序列就会产生对:.Select(g => new { First = g.ElementAt(0), Second = g.ElementAt(1) })
    • 这仅在 2 个可观察序列属于同一类型时才有效。 OP 提到 1 个流是“上下文”,另一个是“内容”,这意味着不同类型的数据。
    • @Matthew Finlay 所以你做到了:)
    【解决方案2】:

    所以你有 2 个可观察的序列要配对在一起?

    来自Rxx 的配对以及 GroupBy 可以在这里提供帮助。我认为类似于以下的代码可能会做你想做的事

    var pairs = stream1.Pair(stream2)
           .GroupBy(pair => pair.Switch(source1 => source1.Key, source2 => source2.Key))
           .SelectMany(group => group.Take(2).ToArray()) // each group will have at most 2 results (1 left and 1 right)
           .Select(pair =>
           {
               T1 result1 = default(T1);
               T2 result2 = default(T2);
    
               foreach (var r in pair)
               {
                  if (r.IsLeft) result1 = r.Left;
                  else result2 = r.Right;
               }
    
               return new { result1, result2 };
           });
    

    ```

    我没有测试过,也没有添加任何错误处理,但我认为这就是你想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 2020-01-06
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多