2016-02-02 41 views
2

如果我觀測到了ab,並且我想根據第三個可觀測值c交替觀測,我該怎麼做?大理石圖會是這個樣子:如何創建兩個觀測值之間交替的觀測值

a: -a1---------a2----a3--a4------a5--a6-----a7---- 
b: -b1--b2----b3--b4----------------b5---b6---b7-- 
c: --------c-----------c--------c----------c------ 
        alternate 
    -a1--------b3--b4-----a4---------b5---b6-a7---- 

回答

3

這工作得很好:

var query = 
    a.Publish(pa => 
     b.Publish(pb => 
      c.StartWith("c") 
       .Select((x, n) => n % 2 == 0 ? pa : pb) 
       .Switch())); 

我測試使用此代碼:

var xs = new [] 
{ 
    "a1", "b1", "b2", "c", "b3", 
    "a2", "b4", "a3", "c", "a4", 
    "c", "a5", "b5", "a6", "b6", 
    "c", "a7", "b7", 
} 
    .ToObservable() 
    .Publish(); 

var a = xs.Where(x => x.StartsWith("a")); 
var b = xs.Where(x => x.StartsWith("b")); 
var c = xs.Where(x => x.StartsWith("c")); 

var query = ... 

query.Subscribe(Console.WriteLine); 

xs.Connect(); 

我懂了結果:

a1 
b3 
b4 
a4 
b5 
b6 
a7 

xs.Connect()是使xs觀察的工作作爲一種簡單的方法來產生三個序列纔有必要。

即使作爲擴展方法:

public static IObservable<TSource> Alternate<TSource>(
    this IObservable<TSource> leftSelector, 
    bool startLeft, 
    IObservable<TSource> left, 
    IObservable<TSource> right) 
{ 
    return 
     left.Publish(pl => 
      right.Publish(pr => 
       leftSelector.StartWith(default(TSource)) 
        .Select((x, n) => (n % 2 == (startLeft ? 0 : 1)) ? pl : pr) 
        .Switch())); 
} 
+0

很整齊+1。我在我的回答中對此進行了很少的編輯,以允許「選擇器」不具有交替值的可能性(儘管此處也可以使用「DiscreteUntilChanged」)。 –

1

該解決方案宣佈C作爲Observable<bool>

結果Observable從a和b基於從C最新值發射值。從和B值被包裹到一個容器類Merge

var a = Observable.Range(1, 10); 
var b = Observable.Range(10, 20); 

var merged = a.Select(i => new Container {id = "a", value = i}) 
       .Merge(b.Select(i => new Container {id = "b", value = i})); 

var c = Observable.Return(true); 

var result = merged.CombineLatest(c , (ab, selector) 
        => (selector && ab.id == "a") || (!selector && ab.id == "b") ? ab : null) 
        .Where(i => i != null); 

public class Container 
{ 
    public string id; 
    public int value; 
} 
2

這裏的另一種方式,類似的想法 - 它也讓你指定選擇一個初始值。

關鍵的想法是使用ZipMostRecent以最近的選擇器值壓縮每個值流。然後,我們可以根據選擇器值過濾每個壓縮的流併合並它們。

public static IObservable<TSource> Alternate<TSource>(
    this IObservable<bool> leftSelector, 
    bool startLeft, 
    IObservable<TSource> left, 
    IObservable<TSource> right) 
{ 
    return leftSelector.Publish(
    selector => 
     Observable.Merge(  
     left.Zip(selector.MostRecent(startLeft), Tuple.Create) 
      .Where(l => l.Item2),      
     right.Zip(selector.MostRecent(startLeft), Tuple.Create) 
      .Where(r => !r.Item2))) 
     .Select(res => res.Item1);    
} 

而且,這裏的Enigmativity整潔的做法非常輕微的調整,以這裏適合輸入:

public static IObservable<TSource> Alternate2<TSource>(
    this IObservable<bool> leftSelector, 
    bool startLeft, 
    IObservable<TSource> left, 
    IObservable<TSource> right) 
{ 
    return 
     left.Publish(l => 
      right.Publish(r => 
       leftSelector.StartWith(startLeft) 
        .Select(s => s ? l : r) 
        .Switch()));   
} 
+0

擴展方法的聲明和'Tuple.Create'使這個比我的解決方案更美麗。 +1 – supertopi

+0

我很想知道爲什麼當問題中的'c'可觀察值每次只產生相同的值時,爲什麼使用'this IObservable leftSelector'?爲了使這項工作有效,你需要將「IObservable '的等價物轉換爲'IObservable '。我錯過了什麼嗎? – Enigmativity

+0

@Enigmativity不,你不會錯過任何東西。相反,我使用範圍漸變的黑暗藝術來添加一個有趣但完全沒有要求的特徵;你可能想要決定c如何選擇流而不是交替。我想象的是應用c投影來產生bool流。它沒有真正想過;它與我現在需要構建的功能非常相似,現在我開始思考它。無論如何,我會留下它的興趣,但你是正確的指出它是多餘的要求。 –

相關問題