2012-08-13 18 views
25

鑑於項目的集合,我如何基於謂詞拆分成集2子集?LINQ本身是否支持將一個集合分爲兩部分?

你可以做2個在哪裏搜索,但隨後的運行時間爲2 * N(其中,同時仍然爲O(n),需要兩倍長,顯然不是首選)

IEnumerable<int> even = nums.Where(i => IsEven(i)); 
IEnumerable<int> odd = nums.Where(i => !IsEven(i)); 

你可以這樣做一個單獨的線性傳遞(這裏重構爲一個擴展方法),但這意味着你必須將這些代碼全部拖拽到一起,而更多的自定義代碼使得事情不易維護。

public static void SplitOnPred<T>(
     this IEnumerable<T> collection, 
     Func<T, bool> pred, 
     out IEnumerable<T> trueSet, 
     out IEnumerable<T> falseSet 
    ) { 
     List<T> trueSetList = new List<T>(); 
     List<T> falseSetList = new List<T>(); 
     foreach(T item in collection) { 
      if(pred(item)) { 
       trueSetList.Add(item); 
      } else { 
       falseSetList.Add(item); 
      } 
     } 
     trueSet = trueSetList; 
     falseSet = falseSetList; 
} 

問: LINQ是否有在1個通拆分收取任何原生支持?

+0

爲什麼你需要一個線性路徑? – 2012-08-13 17:04:40

+3

@SaeedAmiri它不是一個真正的需求,以及2線性傳遞是在大多數情況下_good enough_但我從來沒有與_good enough_的表現真的很開心:P – James 2012-08-13 17:06:49

回答

25

LINQ是否有在1個通拆分收取任何原生支持?

沒有內建的方法根據謂詞將集合拆分爲兩個版本。您需要使用自己的方法,類似於您發佈的方法。

最接近內置的方法將是GroupBy(或ToLookup)。您可以通過組奇數或偶數:

var groups = nums.GroupBy(i => IsEven(i)); 

這將分成基礎上的數字是否是奇數或偶數兩個「團」。

5

那麼,如果該邏輯是獨家推出,在你的情況,你可以像

var list = new List<int> {1,2,3,4,5,6,7,8,9,10};  
var result = list.GroupBy(x=> x%2==0); 

result

foreach(var r in result) 
{ 
    if(r.Key) 
    //EVEN 
    else 
    //ODD 
} 
8

裏德·科普塞的回答提到ToLookup,這似乎有吸引力。

var lookup = nums.ToLookup(IsEven); 

其中IsEven與預期的簽名和返回類型的靜態方法。然後

IEnumerable<int> even = lookup[true]; 
IEnumerable<int> odd = lookup[false]; 
1

如果你想支持延遲執行,使用功能或擴展這樣的:

IEnumerable<T> Split<T>(this IEnumerable<T> source, out IEnumerable<T> odd) 
{ 
    IList<T> oddCollector = new List<T>(); 
    Bool odd = true; 
    foreach(T item in source) 
    { 
     if(odd) 
     { 
      oddCollector.Add(item); 
     } 
     else 
     { 
      yield return item; 
     } 
     odd = !odd; 
    } 
} 

我道歉,任何小型編譯器錯誤,我這樣做從我的頭頂。您可以添加謂詞,而不是偶數/奇數。

+0

警告這僅支持延遲執行,如果你無論是讀甚至第一,或讀兩可交換順序的枚舉。如果你首先讀到奇數,你將不會得到所有的結果。 – csauve 2016-11-11 16:40:07

相關問題