2017-09-30 4 views
2

私は、観察可能なシーケンスを別々のシーケンスに分割して、与えられた述語に基づいて独立して処理できる方法を探しています。私が思い付くことができました最も近い2つのwhereのフィルタをやっているC#のobservablesを分割する

var (evens, odds) = observable.Partition(x => x % 2 == 0); 
var strings = evens.Select(x => x.ToString()); 
var floats = odds.Select(x => x/2.0); 

が、それは、私は野生ではないよこれ、状態を評価し、二回ソースシーケンスを処理する必要があります。このような何かが理想的です約。

observable = observable.Publish().RefCount(); 
var strings = observable.Where(x => x % 2 == 0).Select(x => x.ToString()); 
var floats = observable.Where(x => x % 2 != 0).Select(x => x/2.0); 

F#がObservable.partition<'T>Observable.split<'T,'U1,'U2>で、このための良いサポートを持っているようだが、私は、C#のための同等の何かを見つけることができていませんでした。

+0

あなたは常にF#のライブラリに引っ張るとC# –

+0

探しからそれを使用することができますF#のソースコードでは、ソースストリームに2つのフィルタを実際に適用するように見えるので、基本的に2つの 'wheres'を持つ私の提案と同じです。 – spencercw

答えて

0

どう

var (odds,evens) = (collection.Where(a=> a % 2 == 1), collection.Where(a=> a % 2 == 0));? 

のようなものについてまたはあなたが一つの条件私はあなたが二度この方法の項目を反復処理しているという事実を中心に作業がないと思います

Func<int,bool> predicate = a => a%2==0; 

var (odds,evens) = (collection.Where(a=> !predicate(a)), collection.Where(a=> predicate(a))); 

に基づいてパーティションを作成する場合は、述語を受け取り、2つのsepatateコレクションを渡し、foreachまたはforの1回の反復でそれらを移入するメソッドを持つことが他に可能です。このような

何か:

var collection = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

Func<int,bool> predicate = a => a%2==0; 
var odds = new List<int>(); 
var evens = new List<int>(); 

Action<List<int>, List<int>, Func<int, bool>> partition = (collection1, collection2, pred) => 
{ 
    foreach (int element in collection) 
    { 
     if (pred(element)) 
     { 
      collection1.Add(element); 
     } 
     else 
     { 
      collection2.Add(element); 
     } 
    } 
}; 

partition(evens, odds, predicate); 

最後のアイデアを拡張し、あなたはこのような何かを探していますか?

public static (ObservableCollection<T>, ObservableCollection<T>) Partition<T>(this ObservableCollection<T> collection, Func<T, bool> predicate) 
{ 
    var collection1 = new ObservableCollection<T>(); 
    var collection2 = new ObservableCollection<T>(); 

    foreach (T element in collection) 
    { 
     if (predicate(element)) 
     { 
      collection1.Add(element); 
     } 
     else 
     { 
      collection2.Add(element); 
     } 
    } 

    return (collection1, collection2); 
} 
+0

あなたのアイデアをお寄せいただきありがとうございます。 'ObservableCollection'を使った提案は正しい行に沿っていますが、私はコレクションではなく観測可能なシーケンス(' IObservable')を扱っていますので、無限のシーケンスかもしれないので新しいシーケンスを直ちに返す必要があります。私は「科目」のペアを作成する何かを調理しましたが、それは大きなものです、そして、私は何か存在することを望んでいました。 – spencercw

+0

今のところ、タプルでリアルタイムに「収穫」することはないでしょう。メソッドの中でそれらを作成し、IObservablesを渡して、シーケンスが変更されたときにコールを代行することはありません。 – Vnvizitiu

2

GroupByあなたはまだWhere句になってしまいますが、「二回観察」制限を削除することがあります。

public static class X 
{ 
    public static (IObservable<T> trues, IObservable<T> falsies) Partition<T>(this IObservable<T> source, Func<T, bool> partitioner) 
    { 
     var x = source.GroupBy(partitioner).Publish().RefCount(); 
     var trues = x.Where(g => g.Key == true).Merge(); 
     var falsies = x.Where(g => g.Key == false).Merge(); 
     return (trues, falsies); 
    } 
} 
+0

ニース。私は 'GroupBy'で何かできるかもしれないと思ったが、' Merge'は私が行方不明だったステップでした。ありがとう。 – spencercw

+0

実際には、ソースシーケンスが2回評価されるように見えます。ダム – spencercw

+0

私の怠け者、おっと。更新されたコード:Var xはPublished + Refcountedにする必要があります。利点は、フィルタ関数が高価な場合は、1回だけ実行されることです。 – Shlomo