2012-08-13 15 views
25

Biorąc pod uwagę kolekcję przedmiotów, w jaki sposób podzielić kolekcję na dwie pod-kolekcje na podstawie predykatu?Czy LINQ natywnie obsługuje dzielenie kolekcji na dwie części?

Można do 2, w którym wyszukiwanie, ale czas pracy wynosi 2 * N (która jednocześnie O (n) jest dwa razy długo i nie jest oczywiście korzystny)

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

Można zrobić pojedyncza liniowa przepustka (tutaj refaktoryzowana w metodę rozszerzenia), ale oznacza to, że musisz przeciągnąć ten kod do końca, a więcej niestandardowego kodu sprawia, że ​​rzeczy są mniej łatwe w utrzymaniu.

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; 
} 

Pytanie: Czy LINQ jakieś natywne wsparcie dla podziału kolekcji w 1 liniowym Pass?

+0

Dlaczego potrzebujesz jednej ścieżki liniowej? –

+3

@SaeedAmiri nie jest tak naprawdę wymogiem, a 2 liniowe przebiegi są wystarczająco dobre w większości przypadków, ale nigdy nie jestem naprawdę zadowolony z _good wystarczającej wydajności: P – James

Odpowiedz

25

Czy LINQ ma jakieś natywne wsparcie dla dzielenia kolekcji w 1 przebiegu liniowym?

Nie ma wbudowanych metod, które dzielą kolekcję na dwie wersje na podstawie predykatu. Będziesz musiał użyć własnej metody, podobnej do tej, którą opublikowałeś.

Najbliższa metoda wbudowana to GroupBy (lub ToLookup). Można by grupa przez parzysty, czy nieparzysty:

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

To podzielona na dwie „grupy” na podstawie tego, czy numery są parzysty, czy nieparzysty.

5

Dobrze jeśli logika jest esclusive w sprawy można zrobić jak

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

aw result

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

odpowiedź Reed Copsey wspomina ToLookup, a to wydaje się atrakcyjna.

var lookup = nums.ToLookup(IsEven); 

gdzie IsEven jest metodą statyczną z oczekiwaną typ sygnatury i powrotnego. Następnie

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

Jeśli chcesz wesprzeć wykonanie odroczony, użyj funkcji lub rozszerzenie tak:

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; 
    } 
} 

moje przeprosiny dla każdego małego błędu kompilatora, zrobiłem to z wierzchu głowy. Zamiast wartości parzystej/nieparzystej można dodać predykat.

+0

OSTRZEŻENIE To obsługuje tylko odroczone wykonanie, jeśli przeczytałeś nawet pierwszy, lub przeczytałeś dwa wyliczenia w naprzemiennej kolejności. Jeśli przeczytasz najpierw jako nieparzyste, nie uzyskasz wszystkich wyników. – csauve

Powiązane problemy