wake-up-neo.com

Generische Liste FindAll () vs. Foreach

Ich schaue in einer generischen Liste nach Elementen, die auf einem bestimmten Parameter basieren.

Was wäre im Allgemeinen die beste und schnellste Implementierung?
1. Durchlaufen Sie jedes Element in der Liste und speichern Sie jede Übereinstimmung in einer neuen Liste und geben Sie diese zurück

foreach(string s in list)
{ 
    if(s == "match")
    {
       newList.Add(s);
    }
} 

return newList;

Oder
2. Verwenden der FindAll-Methode und Übergeben eines Delegaten.

newList = list.FindAll(delegate(string s){return s == "match";});

Laufen sie nicht beide in ~ O (N)? Was wäre die beste Praxis hier?

Viele Grüße, Jonathan

29
jon37

Sie sollten auf jeden Fall die FindAll-Methode oder die entsprechende LINQ-Methode verwenden. Erwägen Sie auch, das knappere Lambda anstelle Ihres Delegierten zu verwenden, wenn Sie können (erfordert C # 3.0):

var list = new List<string>();
var newList = list.FindAll(s => s.Equals("match"));
45
Egil Hansen

Ich würde in diesem Fall die FindAll -Methode verwenden, da sie prägnanter ist und IMO eine einfachere Lesbarkeit aufweist.

Sie haben Recht, dass sie so ziemlich beide in O(N) Zeit aufführen werden, obwohl die foreach Anweisung sollte etwas schneller sein , vorausgesetzt, es muss kein Delegatenaufruf ausgeführt werden (Delegaten verursachen einen geringfügigen Mehraufwand im Gegensatz zu Methoden direkt aufrufen).

Ich muss betonen, wie unbedeutend dieser Unterschied ist, es wird höchstwahrscheinlich nie einen Unterschied bewirken, wenn Sie nicht eine massive Anzahl von Operationen an einer massive Liste.

Testen Sie wie immer, wo sich die Engpässe befinden, und handeln Sie entsprechend.

9
casperOne

Jonathan,

Eine gute Antwort darauf finden Sie in Kapitel 5 (Überlegungen zur Leistung) von Linq To Action

Sie messen a für jede Suche, die etwa 50-mal ausgeführt wird und die foreach = 68 ms pro Zyklus/List ergibt. Wirklich, es wäre wahrscheinlich in Ihrem Interesse, einfach einen Test zu erstellen und sich selbst davon zu überzeugen.

5
matt_dev

List.FindAll ist O(n) und durchsucht die gesamte Liste.

Wenn Sie einen eigenen Iterator mit foreach ausführen möchten, würde ich empfehlen, die Yield-Anweisung zu verwenden und wenn möglich ein IEnumerable zurückzugeben. Wenn Sie am Ende nur ein Element Ihrer Sammlung benötigen, ist dies schneller (da Sie Ihren Anrufer anhalten können, ohne die gesamte Sammlung zu erschöpfen).

Andernfalls bleiben Sie bei der BCL-Schnittstelle.

4
Reed Copsey

Jeder Perf-Unterschied wird extrem gering sein. Ich würde FindAll aus Gründen der Übersichtlichkeit vorschlagen oder, falls möglich, Enumerable.Where. Ich bevorzuge die Verwendung der Enumerable-Methoden, da sie eine größere Flexibilität bei der Umgestaltung des Codes ermöglichen (Sie brauchen keine Abhängigkeit von List<T>).

3
Daniel Pratt

Ja, beide Implementierungen sind O (n). Sie müssen sich jedes Element in der Liste ansehen, um alle Übereinstimmungen zu finden. Im Hinblick auf die Lesbarkeit würde ich auch FindAll bevorzugen. Zu Leistungsaspekten siehe LINQ in Aktion (Kap 5.3). Wenn Sie C # 3.0 verwenden, können Sie auch einen Lambda-Ausdruck anwenden. Aber das ist nur das Sahnehäubchen:

var newList = aList.FindAll(s => s == "match");
2
olli-MSFT

Ich bin mit den Lambdas

List<String> newList = list.FindAll(s => s.Equals("match"));
1
MRFerocius

Sofern das C # -Team die Leistung für LINQ und FindAll nicht verbessert hat, scheint der folgende Artikel zu vermuten, dass for und foreachLINQ und FindAll bei der Objektaufzählung übertreffen würden: LINQ on Objects Performance

Dieser Artikel wurde auf März 2009 datiert, kurz bevor dieser Beitrag ursprünglich gestellt wurde.

0
William Niu