2010-07-08 4 views
7

Ich habe als Liste der Zeichenfolgen mit, wo ich jedes Duplikate entfernen, jetzt möchte ich es noch mehr filtern, um die letzten 5 Datensätze zu erhalten. Wie kann ich das machen?So erhalten Sie die letzten x Datensätze aus einer Liste mit Lambda

Was habe ich bisher

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

Warum die 'Select (a => a)'? Es tut nichts ... – tzaman

+0

das war mein "Dummy", um den letzten x records filter – Ivo

Antwort

9

Sie benötigen keine .Select(a => a). Das ist überflüssig.

Sie können die letzten fünf Datensätze erhalten, indem Sie den Rest Überspringen wie

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

Skip() hat eine bessere Leistung als Reverse() dann Take(), offensichtlich. –

+0

@Danny: Nicht so viel wie du denkst: der 'ToList()' Aufruf ist genauso teuer wie mein erster 'Reverse()' (durchquere die ganze Liste einmal) und nach dem 'Take (5)' Es ist nur fünf Elemente umzukehren, die Erdnüsse sind. Außerdem erstellt mein Weg keine Zwischenliste. – tzaman

+0

@tzaman - "mein Weg schafft keine Zwischenliste" - ja, tut es; zwei von ihnen in der Tat. Wie denken Sie, dass "Reverse" funktioniert? (Nun, streng genommen erzeugt es ein 'T []' Array, mit freundlicher Genehmigung von 'Buffer '- aber gleicher Unterschied) –

4

Wie wäre das?

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

edit: hier ist die ganze Sache -

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

Beachten Sie auch, dass Sie es nicht query nennen sollten, wenn Sie einen ToList() Anruf am Ende haben, denn dann ist es keine Abfrage mehr, es wurde ausgewertet und in eine Liste umgewandelt. Wenn Sie es nur zum Iterieren benötigen, können Sie den ToList()-Aufruf weglassen und ihn als IEnumerable belassen.

+1

Ich würde wagen, dass es billiger wäre, die Elemente zu zählen, dann Skip und Take verwenden. Die Umkehrung eines IEnumerable kann nicht billig sein. – spender

+0

Es ist die gleiche asymptotische Komplexität wie auch immer, aber Sie haben Recht, dass skip/take wahrscheinlich schneller ist. – tzaman

+0

Eigentlich werde ich meine frühere Aussage ändern - ich denke nicht, dass es einen merklichen Leistungsunterschied geben wird. Siehe meinen Kommentar zu Jens Antwort. – tzaman

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

EDIT:

Ich vermisste, dass die Datenliste ist < T>. Dieser Ansatz wäre besser für IEnumerable < T>

5

bearbeiten für Nicht-Liste Eingänge gerecht zu werden, jetzt Griffe IEnumerable<T> und prüft wenn dies ein IList<T>; wenn nicht, puffert es über ToList(), was dazu beiträgt sicherzustellen, dass wir nur die Daten einmal lesen (anstatt .Count() und .Skip(), die die Daten mehrmals lesen können).

Da dies eine Liste ist, würde ich geneigt sein, eine Erweiterungsmethode zu schreiben, die auf den vollen dass verwendet:

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

Absolut. Wenn Sie wissen, dass es eine Liste ist, ist dies ein einfacher und leicht effizienter Weg. – Noldorin

+0

Außer es wird keine Liste sein, wenn es aus dem 'Distinct()' Anruf kommt; Die 'ToList()' muss nur einmal am Ende passieren. – tzaman

+0

@tzaman - gut; wird bearbeiten –

Verwandte Themen