2010-07-08 11 views
7

Mam jako Listę ciągów, z których usuwam każde duplikaty, teraz chcę filtrować jeszcze więcej, aby uzyskać 5 ostatnich rekordów. Jak mogę to zrobić?Jak zdobyć ostatnie x rekordów z listy z Lambdą

Co mam tak daleko

List<string> query = otherlist.Distinct().Select(a => a).ToList(); 
+0

Dlaczego 'Select (a => a)'? To nic nie robi ... – tzaman

+0

to był mój "manekin", aby umieścić ostatni filtr rekordów x. – Ivo

Odpowiedz

9

Nie potrzebujesz .Select(a => a). To jest zbyteczne.

można dostać ostatnie 5 rekordów, omijając nad resztą jak

List<string> query = otherlist.Distinct().ToList(); 
List<string> lastFive = query.Skip(query.Count-5).ToList(); 
+0

Skip() ma lepszą wydajność niż Reverse(), a następnie Take(), oczywiście. –

+0

@Danny: Nie tak bardzo, jak myślisz: wywołanie 'ToList()' będzie tak samo drogie jak moje pierwsze 'Reverse()' (przemierza całą listę raz) i po 'Take (5)' po prostu odwraca pięć elementów, czyli orzeszki ziemne. Ponadto moja droga nie tworzy pośredniej listy. – tzaman

+0

@tzaman - "moja droga nie tworzy pośredniej listy" - tak, robi; w rzeczywistości dwie. Jak myślisz, jak działa "Reverse"? (cóż, ściśle rzecz biorąc tworzy tablicę 'T []', dzięki uprzejmości 'Buffer ' - ale ta sama różnica) –

4

Jak chodzi?

var lastFive = list.Reverse().Take(5).Reverse(); 

edit: oto cała sprawa -

var lastFiveDistinct = otherlist.Distinct() 
           .Reverse() 
           .Take(5) 
           .Reverse() 
           .ToList(); 

Należy również pamiętać, że nie należy nazwać query jeśli masz ToList() wezwanie na końcu, bo wtedy to nie się zapytanie już zostało ocenione i zostało przekształcone w listę. Jeśli potrzebujesz go tylko do iteracji, możesz pominąć wywołanie ToList() i pozostawić je jako IEnumerable.

+1

Zaryzykowałbym, że taniej byłoby zliczyć elementy, a następnie użyć Pomiń i weź. Odwracanie IEnumerable nie może być tanie. – spender

+0

Tak samo złożona jest złożoność asymptotyczna, ale masz rację, że pomijanie/branie jest prawdopodobnie szybsze. – tzaman

+0

Właściwie zmienię moje wcześniejsze oświadczenie - nie sądzę, aby wystąpiła zauważalna różnica w wydajności. Zobacz mój komentarz do odpowiedzi Jensa. – tzaman

0
var count=list.Count(); 
var last5=list.Skip(count-5); 

EDIT:

brakowało mi się, że dane jest Lista < T>. Takie podejście byłoby lepiej dla IEnumerable < T>

5

edycji zaspokoić wejść spoza listy, teraz obsługuje IEnumerable<T> i kontrole jeśli jest to IList<T>; jeśli nie, buforuje go przez ToList(), co pomaga zapewnić, że odczytujemy dane tylko raz (zamiast i .Skip(), które mogą odczytywać dane wiele razy).

Ponieważ jest to lista, byłbym skłonny napisać metodę rozszerzenia, które wykorzystuje, że w pełni:

public static IEnumerable<T> TakeLast<T>(
      this IEnumerable<T> source, int count) 
    { 
     IList<T> list = (source as IList<T>) ?? source.ToList(); 
     count = Math.Min(count, list.Count); 
     for (int i = list.Count - count; i < list.Count; i++) 
     { 
      yield return list[i]; 
     } 
    } 
+0

Absolutnie. Biorąc pod uwagę, że jest to lista, jest to proste i łatwo najbardziej efektywne podejście. – Noldorin

+0

Z wyjątkiem tego, że nie będzie to lista, jeśli wychodzi z wywołania 'Distinct()'; 'ToList()' musi się zdarzyć tylko raz na końcu. – tzaman

+0

@tzaman - dobrze; będzie edytować –

Powiązane problemy