2013-02-25 107 views
5

讓我們假設序列一出去到網站檢索網站1,2,3,4,5的內容(但將以不可預測的順序返回)。我可以通過匹配鍵將兩個序列組合在一起嗎?

序列二將進入數據庫以檢索關於這些相同記錄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組合。

回答

3
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)); 
+0

哇,太棒了!非常感謝,我沒有意識到我可以用Merge獲得我需要的東西。我把它加到了最後,所以最後的序列會產生一對: 。選擇(g => new {First = g.ElementAt(0),Second = g.ElementAt(1)}) – blaster 2013-02-26 15:51:10

+0

這隻適用於2個可觀察序列具有相同的類型。 OP提到1個流是「上下文」,另一個是「內容」,這意味着不同類型的數據。 – Brandon 2013-02-27 16:22:33

+0

@Brandon,我爲這種情況添加了一個編輯。 – 2013-02-27 23:29:58

1

所以你有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 }; 
     }); 

```

我沒有測試它,並在任何錯誤處理沒有添加什麼,但我認爲這是你想要的。

相關問題