2017-09-30 71 views
2

我正在尋找某種方式將可觀察序列分割成獨立的序列,我可以根據給定的謂詞獨立處理。這樣的事情將是理想的:在C#中對可觀察分區進行分區#

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

最近我已經能夠拿出在做兩個where過濾器,但需要評估的條件和處理源序列兩次,這我不是野生關於。

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#源代碼中,它看起來實際上只是將兩個過濾器應用於源流,因此它與我的兩個'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循環中填充它們。

事情是這樣的:

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'做一些事情,但是'合併'是我錯過的一步。謝謝。 – spencercw

+0

哦,實際上,當你這樣做時,看起來源序列確實會被評估兩次。該死的 – spencercw

+0

哎呀,我很懶。更新的代碼:Var x應該被髮布+ Refcounted。優點是,如果你的過濾功能很貴,那隻能運行一次。 – Shlomo