1

2 つの値ストリームと 1 つのセレクター ストリームがあり、セレクターに基づいて値ストリームを交互に切り替える結果ストリームを生成したいと考えています。以下のコードは正しい結果をもたらしますが、私はそれが好きではありません。

誰かがもっときれいなものを持っていますか?

var valueStreamA = new BehaviorSubject<int>(0);
var valueStreamB = new BehaviorSubject<int>(100);
var selectorStream = new BehaviorSubject<bool>(true);

var filteredA = valueStreamA .CombineLatest(selectorStream, (a, c) => new { A = a, C = c })
  .Where(ac => ac.C)
  .Select(ac => ac.A);
var filteredB = valueStreamB.CombineLatest(selectorStream, (b, c) => new { B = b, C = c })
  .Where(bc => !bc.C)
  .Select(bc => bc.B);

var result = Observable.Merge(filteredA, filteredB);
result.Subscribe(Console.WriteLine);

valueStreamA.OnNext(1);
valueStreamB.OnNext(101);
selectorStream.OnNext(false);

valueStreamA.OnNext(2);
valueStreamB.OnNext(102);
selectorStream.OnNext(true);

これにより、次の出力が生成されます。

0
1
101
102
2
4

3 に答える 3

2

私はこのようなことをします:

var a = new BehaviorSubject<int>(0);
var b = new BehaviorSubject<int>(100);
var c = new BehaviorSubject<bool>(true);

var valueStreamA = a as IObservable<int>;
var valueStreamB = b as IObservable<int>;
var selector = c as IObservable<bool>;

var result = selector
    // for every change in the selector...
    .DistinctUntilChanged()
    // select one of the two value streams
    .Select(change => change ? valueStreamA : valueStreamB)
    // and flatten the resulting wrapped observable
    .Switch();

result.Subscribe(Console.WriteLine);

a.OnNext(1);
b.OnNext(101);
c.OnNext(false);

a.OnNext(2);
b.OnNext(102);
c.OnNext(true);
于 2013-02-07T21:24:43.043 に答える
0

元の質問にはるかに近づきました:

void Main()

{

var valueStreamA = new BehaviorSubject<int>(0);
var valueStreamB = new BehaviorSubject<int>(100);

var selectorStreamA = valueStreamA.Select(id => Tuple.Create("A", id)).Publish();
var selectorStreamB = valueStreamB.Select(id => Tuple.Create("B", id)).Publish();
var selectorStream = new BehaviorSubject<bool>(true);

var query = from selector in selectorStream
            select from merged in selectorStreamA.Merge(selectorStreamB)
                   where selector == true ? merged.Item1 == "A" : merged.Item1 == "B"
                   select merged.Item2;

query.Switch().Subscribe(Console.WriteLine);

selectorStreamA.Connect();
selectorStreamB.Connect();

//First we get 0 output (because we are already using stream A, and it has a first value)
valueStreamA.OnNext(1); //This is output, because our selector remains as 'A'
valueStreamB.OnNext(101); //This is ignored - because we don't take from B
selectorStream.OnNext(false); //Switch to B

valueStreamA.OnNext(2); //Ignored - we are now using B only
valueStreamB.OnNext(102); //This is output
selectorStream.OnNext(true); //Switch back to A.

}

出力:

0 1 102

于 2013-02-07T21:21:54.123 に答える
0

次のようなことができます:

var xs = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => Feeds.Xs);
var ys = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => Feeds.Ys);
var selectorSubject = new Subject<Feeds>();

var query = from selector in selectorSubject
                select from merged in xs.Merge(ys)
                where merged == selector
                select merged;

query.Switch().Subscribe(Console.WriteLine);

OnNext を「selectorSubject」に入力して変更します。あなたの例にはいくつかの違いがありますが、簡単に回避できます。

  1. あなたの質問にはbool型のセレクターが含まれていましたが、私は怠惰でFeeds列挙型を再利用して、簡単な等価チェックを行うことができました(マージされた==セレクター)。もちろん、単純に (where selector ? merged == Xs : merged == Ys)、またはマージされた各アイテムを評価し、気にしないアイテムを破棄するようなこともできます (セレクターによって異なります)。

具体的には、整数だけでなく、フィードの識別子を選択することをお勧めします。Tuple.Create() のようなものを使用することを検討してください。これにより、更新ごとにその情報を取得できます: {A - 1}、{B - 101} など。merged.Item1 == A : merged.Item1 == B //これは「true」をフィード A にマップします

  1. また、Switch も使用しました。これにより、サンプル ストリームは公開されていないため、再起動されます。あなたはおそらくあなたのものを公開してそれらを接続したい(それらを「ホット」にする)ので、私のようなスイッチはサブスクリプションに新しい副作用を引き起こしません. サブジェクト(ホット)がありますが、「動作」部分はコンストラクターに渡した値を置き換えます。公開して接続すると、それが妨げられます。

それでも迷ったら声をかけてください。これは完全な答えではありませんが、考えるには十分かもしれません。

ハワード。

于 2013-02-07T21:01:26.787 に答える