2008-11-26 6 views
276

Ich möchte mit Linq einen Busfahrplan in meinem Projekt abfragen, damit ich jederzeit die nächsten 5 Busankunftszeiten bekommen kann. Wie kann ich meine Anfrage auf die ersten 5 Ergebnisse beschränken?Wie bekomme ich die ersten N Elemente einer Liste in C#?

Allgemeiner, wie kann ich ein Stück einer Liste in C# nehmen? (In Python würde ich mylist[:5] verwenden, um die ersten 5 Elemente zu erhalten.)

Antwort

504
var firstFiveItems = myList.Take(5); 

oder zu schneiden:

var secondFiveItems = myList.Skip(5).Take(5); 

Und natürlich oft ist es zweckmäßig, die ersten fünf Positionen nach irgendeiner Art erhalten von Bestellung:

var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5); 
+55

Wird eine Ausnahme ausgelöst, wenn nur 3 Einträge in der Liste vorhanden sind? Oder dauert es so viele wie bis zu 5? –

+53

@bobek: Es wird keine Ausnahme ausgelöst. Es gibt einfach zurück, was es hat, wenn es nicht genug Elemente gibt. –

+0

genau, keine Ausnahmen geworfen Skip and Take kombiniert löste mein Problem, wie ich eine generische Sammlung nehmen und x Elemente pro Batch verarbeiten wollte – JohanLarsson

57

falls jemand interessiert ist (auch wenn die Frage nicht für diese Version nicht fragen), in C# 2 wäre: (ich die Antwort bearbeitet haben, folgende einige Vorschläge)

myList.Sort(CLASS_FOR_COMPARER); 
List<string> fiveElements = myList.GetRange(0, 5); 
+0

Vielleicht fügen Sie auch ein anonymes Prädikat hinzu? – AlexeyMK

+1

Liste .Sort gibt void zurück; Sie müssten sortieren und dann GetRange separat verwenden. Sie können auch eine anonyme Vergleichsmethode verwenden, um CLASS_FOR_COMPARER zu entfernen. –

+0

@AlexeyMK - Sie meinen einen Vergleich , kein Prädikat (Prädikat ) - ein Prädikat wird verwendet, um Daten zu filtern –

0

ersten 5 Elemente besser wie dieses verwenden nehmen Ausdruck:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

oder

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

wird es schneller sein als orderBy Variante, weil LINQ Engine nicht aufgrund der verzögerten Ausführung durch alle Listen scannen und nicht alle Arrays sortieren.

class MyList : IEnumerable<int> 
{ 

    int maxCount = 0; 

    public int RequestCount 
    { 
     get; 
     private set; 
    } 
    public MyList(int maxCount) 
    { 
     this.maxCount = maxCount; 
    } 
    public void Reset() 
    { 
     RequestCount = 0; 
    } 
    #region IEnumerable<int> Members 

    public IEnumerator<int> GetEnumerator() 
    { 
     int i = 0; 
     while (i < maxCount) 
     { 
      RequestCount++; 
      yield return i++; 
     } 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var list = new MyList(15); 
     list.Take(5).ToArray(); 
     Console.WriteLine(list.RequestCount); // 5; 

     list.Reset(); 
     list.OrderBy(q => q).Take(5).ToArray(); 
     Console.WriteLine(list.RequestCount); // 15; 

     list.Reset(); 
     list.Where(q => (q & 1) == 0).Take(5).ToArray(); 
     Console.WriteLine(list.RequestCount); // 9; (first 5 odd) 

     list.Reset(); 
     list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray(); 
     Console.WriteLine(list.RequestCount); // 9; (first 5 odd) 
    } 
} 
+22

Außer dass Sie jetzt nur die ersten 5 Elemente bestellen, nachdem Sie sie ausgewählt haben. Es mag zwar schneller sein, aber es hat auch andere Semantiken, die weniger wahrscheinlich sind, was die Leute tatsächlich erreichen wollen. –

+3

+1 zu Gregs Kommentar - Nehmen und dann bestellen ist fast immer der falsche Ansatz, IMO. –

+0

Ich denke, es hängt davon ab, was Sie für das Ergebnis wollen, es ist keine einfache Frage schwarz oder weiß. –

Verwandte Themen