Was ist der "beste" Weg (unter Berücksichtigung von Geschwindigkeit und Lesbarkeit), um festzustellen, ob eine Liste leer ist? Auch wenn die Liste vom Typ ist IEnumerable<T>
und keine Count-Eigenschaft hat.
Im Moment werfe ich dazwischen:
if (myList.Count() == 0) { ... }
und das:
if (!myList.Any()) { ... }
Ich vermute, dass die zweite Option schneller ist, da sie ein Ergebnis liefert, sobald das erste Element angezeigt wird, während die zweite Option (für eine IEnumerable) jedes Element besuchen muss, um die Anzahl zurückzugeben.
Abgesehen davon, erscheint Ihnen die zweite Option als lesbar? Was würdest du bevorzugen? Oder können Sie sich einen besseren Weg vorstellen, um eine leere Liste zu testen?
Die Antwort von Edit @ lassevk scheint die logischste zu sein, verbunden mit ein wenig Laufzeitprüfung, um wenn möglich eine zwischengespeicherte Anzahl zu verwenden, wie folgt:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
is
undcast
sondern verwendenas
undnull
prüfen:ICollection<T> collection = list as ICollection<T>; if (collection != null) return colllection.Count;
list.Any()
gleichbedeutend mitlist.IsEmpty
? Die Framework-Methode sollte optimiert werden - es lohnt sich nur, eine neue zu schreiben, wenn Sie herausgefunden haben, dass es sich um einen Perf-Engpass handelt.IsEmpty
Erweiterungsmethode hinzufügt . github.com/dotnet/corefx/issues/35054 Bitte überprüfen und stimmen Sie ab, wenn Sie möchten und zustimmen.Antworten:
Sie könnten dies tun:
Bearbeiten : Beachten Sie, dass die einfache Verwendung der .Count-Methode schnell ist, wenn die zugrunde liegende Quelle tatsächlich über eine Fast Count-Eigenschaft verfügt. Eine gültige Optimierung oben wäre, einige Basistypen zu erkennen und einfach die .Count-Eigenschaft dieser anstelle des .Any () -Ansatzes zu verwenden, dann aber auf .Any () zurückzugreifen, wenn keine Garantie gegeben werden kann.
quelle
IsNullOrEmpty()
.return !source?.Any() ?? true;
Ich würde eine kleine Ergänzung zu dem Code machen, auf den Sie sich anscheinend festgelegt haben: Überprüfen Sie auch
ICollection
, ob dies auch von einigen nicht veralteten generischen Klassen implementiert wird (dhQueue<T>
undStack<T>
). Ich würde auchas
anstelle von verwenden,is
da es idiomatischer ist und sich als schneller erwiesen hat .quelle
NotSupportedException
oder nicht vollständig implementierenNotImplementedException
. Ich habe Ihr Codebeispiel zum ersten Mal verwendet, als ich herausfand, dass eine von mir verwendete Sammlung eine Ausnahme für Count auslöste (wer wusste ...).Überrascht dich das? Ich stelle mir vor, dass bei
IList
ImplementierungenCount
einfach die Anzahl der Elemente direkt gelesen wird, währendAny
dieIEnumerable.GetEnumerator
Methode abgefragt , eine Instanz erstellt undMoveNext
mindestens einmal aufgerufen werden muss./ EDIT @Matt:
Ja, natürlich. Das habe ich gemeint. Eigentlich wird es
ICollection
anstelle von verwendet,IList
aber das Ergebnis ist das gleiche.quelle
Ich habe gerade einen kurzen Test geschrieben. Versuchen Sie Folgendes:
Der zweite ist fast dreimal langsamer :)
Wenn Sie den Stoppuhr-Test erneut mit einem Stack oder Array oder anderen Szenarien versuchen, hängt dies wirklich von der Art der Liste ab, die es scheint - denn sie beweisen, dass Count langsamer ist.
Ich denke, es hängt von der Art der Liste ab, die Sie verwenden!
(Nur um darauf hinzuweisen, ich habe mehr als 2000 Objekte in die Liste aufgenommen und die Zählung war immer noch schneller, im Gegensatz zu anderen Typen)
quelle
Enumerable.Count<T>()
hat spezielle Handhabung fürICollection<T>
. Wenn Sie dies mit etwas anderem als einer Basisliste versuchen , werden Sie wahrscheinlich signifikant unterschiedliche (langsamere) Ergebnisse sehen.Any()
wird aber ungefähr gleich bleiben.Enumerable.Any<T>()
für gibtICollection<T>
? Sicherlich könnte der ParameterloseAny()
auch dieCount
Eigenschaft überprüfenICollection<T>
?List.Count
ist O (1) gemäß der Dokumentation von Microsoft:http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
Verwenden Sie
List.Count == 0
es einfach viel schneller als eine AbfrageDies liegt daran, dass es ein Datenelement namens Count hat, das jedes Mal aktualisiert wird, wenn etwas zur Liste hinzugefügt oder daraus entfernt wird. Wenn Sie also aufrufen
List.Count
, muss es nicht jedes Element durchlaufen, um es abzurufen, sondern gibt nur das Datenelement zurück.quelle
Die zweite Option ist viel schneller, wenn Sie mehrere Elemente haben.
Any()
kehrt zurück, sobald 1 Artikel gefunden wurde.Count()
muss die gesamte Liste durchgehen.Angenommen, die Aufzählung enthält 1000 Elemente.
Any()
würde den ersten überprüfen und dann true zurückgeben.Count()
würde 1000 zurückgeben, nachdem die gesamte Aufzählung durchlaufen wurde.Dies ist möglicherweise schlimmer, wenn Sie eine der Prädikatüberschreibungen verwenden - Count () muss immer noch jedes einzelne Element überprüfen, auch wenn es nur eine Übereinstimmung gibt.
Man gewöhnt sich an die Verwendung von Any one - es macht Sinn und ist lesbar.
Eine Einschränkung: Wenn Sie eine Liste haben und nicht nur eine IEnumerable, verwenden Sie die Count-Eigenschaft dieser Liste.
quelle
@Konrad Was mich überrascht ist, dass ich in meinen Tests die Liste an eine akzeptierende Methode übergebe
IEnumerable<T>
, sodass die Laufzeit sie nicht durch Aufrufen der Count () - Erweiterungsmethode für optimieren kannIList<T>
.Ich kann nur davon ausgehen, dass die Count () - Erweiterungsmethode für IEnumerable ungefähr so funktioniert:
... mit anderen Worten, ein bisschen Laufzeitoptimierung für den Sonderfall von
IList<T>
./ EDIT @Konrad +1 Kumpel - Sie haben Recht damit, dass es wahrscheinlicher ist, dass es eingeschaltet ist
ICollection<T>
.quelle
Ok, was ist mit diesem?
EDIT: Ich habe gerade festgestellt, dass jemand diese Lösung bereits skizziert hat. Es wurde erwähnt, dass die Any () -Methode dies tun wird, aber warum nicht selbst? Grüße
quelle
using
Block einschließen, da Sie sonst einIDisposable
Objekt konstruiert und es dann aufgegeben haben. Dann, natürlich, wird es mehr prägnantes , wenn Sie die Erweiterungsmethode verwenden , die bereits vorhanden ist und es nur ändernreturn !enumerable.Any()
(was tut genau dies).Any()
genau das ausgeführt, sodass das Hinzufügen genau derselben Methode mit einem anderen Namen nur verwirrend ist.Eine andere Idee:
Ich mag jedoch den Any () -Ansatz mehr.
quelle
Dies war wichtig, damit dies mit Entity Framework funktioniert:
quelle
Wenn ich mit Count () überprüfe, führt Linq ein "SELECT COUNT (*) .." in der Datenbank aus, aber ich muss überprüfen, ob die Ergebnisse Daten enthalten, habe ich beschlossen, FirstOrDefault () anstelle von Count () einzuführen.
Vor
Nach dem
quelle
quelle
Hier ist meine Umsetzung der Antwort von Dan Tao unter Berücksichtigung eines Prädikats:
quelle
quelle
myList.ToList().Count == 0
. Das ist allesquelle
Diese Erweiterungsmethode funktioniert bei mir:
quelle