2009-03-23 21 views
27

Ich schaue durch eine generische Liste, um Elemente basierend auf einem bestimmten Parameter zu finden.Generische Liste FindAll() vs. foreach

Allgemein, was wäre die beste und schnellste Implementierung?
1. Looping durch jedes Element in der Liste und jedes Spiel zu einer neuen Liste speichern und Rückkehr, dass

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

return newList; 

Oder
2. FindAll Methode verwenden und es einen Delegierten übergeben.

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

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

Grüße, Jonathan

Antwort

41

Sie sollten unbedingt die Methode FindAll oder die entsprechende LINQ-Methode verwenden. Denken Sie auch daran, das prägnantere Lambda anstelle Ihres Delegaten zu verwenden, wenn Sie können (erfordert C# 3.0):

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

würde ich die FindAll method in diesem Fall verwenden, da es prägnanter und IMO ist, hat bessere Lesbarkeit.

Sie haben Recht, dass sie ziemlich viel beide gehen in O (N) Zeit durchführen, obwohl die foreach statementleicht schneller gegeben sein sollte es nicht einen Delegate-Aufruf auszuführen hat (die Delegierten eine leichte entstehen Overhead im Gegensatz zu direkten Aufrufmethoden).

muß ich betonen, wie unbedeutend ist dieser Unterschied, es ist mehr als wahrscheinlich nie einen Unterschied machen gehen, wenn Sie eine massive Anzahl der Operationen auf eine massiven Liste tun.

Wie immer, um zu sehen, wo die Engpässe sind und angemessen handeln.

4

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

Wenn Sie einen eigenen Iterator mit foreach ausführen möchten, empfehle ich, die Yield-Anweisung zu verwenden und, wenn möglich, ein IEnumerable zurückzugeben. Wenn Sie auf diese Weise nur ein Element Ihrer Sammlung benötigen, ist dies schneller (da Sie Ihren Anrufer stoppen können, ohne die gesamte Sammlung zu beanspruchen).

Ansonsten bleiben Sie an der BCL-Schnittstelle.

3

Jede Leistungsdifferenz wird sehr gering sein. Ich würde FindAll für Klarheit oder, wenn möglich, Enumerable vorschlagen. Ich bevorzuge die Verwendung der Enumerable-Methoden, weil es eine größere Flexibilität beim Refactoring des Codes erlaubt (Sie nehmen keine Abhängigkeit von List<T>).

5

Jonathan,

Eine gute Antwort, die Sie dazu finden Sie im Kapitel 5 (Leistungsinformationen) von Linq To Action.

Sie messen eine für jede Suche, die etwa 50 mal ausgeführt wird, und das ergibt foreach = 68ms pro Zyklus/List.FindAll = 62ms pro Zyklus. Wirklich, es wäre wahrscheinlich in Ihrem Interesse, nur einen Test zu erstellen und selbst zu sehen.

2

Ja, beide Implementierungen sind O (n). Sie müssen jedes Element in der Liste betrachten, um alle Übereinstimmungen zu finden. In Bezug auf die Lesbarkeit würde ich auch FindAll bevorzugen. Für Leistungsüberlegungen werfen Sie einen Blick auf LINQ in Action (Ch 5.3). Wenn Sie C# 3.0 verwenden, können Sie auch einen Lambda-Ausdruck anwenden. Aber das ist nur das Tüpfelchen auf dem i:

var newList = aList.FindAll(s => s == "match"); 
1

Im mit den Lambdas

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

Es sei denn, das C# Team die Leistung für LINQ und FindAll verbessert hat, scheint der folgende Artikel zu zeigen, dass for und foreach würde übertreffen LINQ und FindAll auf Objekt-Enumeration: LINQ on Objects Performance.

Diese Artilce wurde zurück bis März 2009, kurz bevor diese Post ursprünglich gefragt.