Wozu dient .Any () in einer C # -Liste <>?

40

Ich habe diese Diskussion mit Kollegen, und wir können nicht herausfinden , was die Verwendung ist .Anyfür jeden gegebenen List<>, in C #.

Sie können die Gültigkeit eines Elements im Array wie folgt überprüfen:

if (MyList.Any()){ ...}  //Returns true or false

Welches ist genau das gleiche wie

if (MyList.Count() != 0) { ... }

und ist viel häufiger, lesbar und klar über die Absicht der ifAussage.

Am Ende waren wir mit diesem Gedanken festgefahren:

.Any() verwendet werden kann, wird genauso gut funktionieren, ist aber weniger klar über die Absicht des Programmierers, und in diesem Fall sollte es nicht verwendet werden.

Aber wir haben das Gefühl, dass das nicht richtig sein kann. Wir müssen etwas vermissen.

Sind wir?

Gil Sand
quelle
40
Inwiefern ist die Absicht weniger klar?
jk.
35
Ich wende mich gegen Ihre Behauptung, Any()die weniger klar ist: Any()scheint mir klarer zu sein, insbesondere bei einer Lambda-Erkrankung. Wenn ich den Code in meinem Kopf ins Englische übersetze, if(MyList.Count(o => o > 10) > 0)wird "Ist die Anzahl der Artikel größer als 10 größer als 0?" während if(MyList.Any(o => o > 10))wird „Gibt es irgendwelche Gegenstände von mehr als 10?“
BlueRaja - Danny Pflughoeft
3
@SargeBorsch - nur wenn Sie Heskel / funktionale Benennung bevorzugen, was die meisten Leute nicht tun.
Davor Ždralo
4
@ BlueRaja-DannyPflughoeft da stimme ich zu. Ich denke, jeder ist klarer, da er eine magische Zahl eliminiert.
Andy
2
@SargeBorsch: Die SQL parallel zu Anyist Exists. Der Name Linq ist wahrscheinlich eher von Haskell und Python inspiriert, die ebenfalls alle Funktionen haben.
JacquesB

Antworten:

95

Denken Sie daran, dass Anynicht auf einem operiert List; Es wird auf einer ausgeführt IEnumerable, die einen konkreten Typ darstellt, der eine CountEigenschaft haben kann oder nicht . Es ist wahr, dass es nicht unbedingt das Beste ist, um es auf einem zu verwenden List, aber es ist definitiv nützlich am Ende einer LINQ-Abfrage. Und noch nützlicher als die Standalone-Version ist die Überschreibung, die ein Prädikat wie folgt annimmt Where. Es gibt nichts, Listwas so praktisch oder aussagekräftig ist wie die Prädikaterweiterungsmethode Any.

Wenn Sie Count()(die LINQ-Erweiterungsmethode für IEnumerable) anstelle von Count(die Eigenschaft on List) verwenden, muss möglicherweise die gesamte Sequenz aufgelistet werden, wenn dies nicht durch die Erkennung einer CountEigenschaft des zugrunde liegenden Datentyps optimiert werden kann . Wenn Sie eine lange Folge haben, kann dies einen spürbaren Leistungseinbußen, wenn Sie nicht wirklich interessieren , was die Zählung ist, und möchte nur wissen , ob es irgendwelche Elemente in der Auflistung.

Mason Wheeler
quelle
19
Diese. Leistung zur Seite, Any()mit einem Prädikat ist mehr ausdrucksvoller als Vergleich die Überschreibung des Enumerable.Count()das braucht ein Prädikat mit 0 :)
Dan J
1
Ich denke, dies erklärt die Grundlagen so klar, dass die Antwort bestenfalls erklärt wird.
Tarik
2
IMHO, Existsist genauso bequem und ausdrucksstark wie Anymit einem Prädikat. Die Verwendung von Count != 0property auf a Listist normaler als die Verwendung von Any(). Es ist nur eine persönliche Präferenz. Ich habe mich auch bemüht _list_.Count(), _list_.Countin den Code meiner Gruppe zu wechseln . Es machte einen spürbaren Unterschied für mich.
Suncat2000
55

Es gibt eine Laufzeitdifferenz, Count()die O (n) sein kann, wobei Any()O (1) ist.

Schild
quelle
15
Count()wird auch nicht für unendliche Iteratoren anhalten, während Any()es nur MoveNext()einmal aufgerufen werden muss.
Jon Purdy
3
Prägnant und genau, aber dies ist eher ein Kommentar als eine Antwort. Programmierer bevorzugen Antworten, die sich mit dem Warum befassen und ein gewisses Maß an Erklärung liefern. Erwägen Sie , Ihre Antwort zu bearbeiten und zu erläutern, warum O (1) wichtig sein könnte (ist).
Sehr gute Antwort Ich habe gerade gelernt, ich sollte keine anstelle von count == 0: d
MonsterMMORPG
4
Any(Func<T>)ist es O (n)
BlueRaja - Danny Pflughoeft?
1
Im speziellen Fall von Listist die Leistung gleich, da die Erweiterung die Eigenschaft verwendet. True für alle Sammlungen, die die ICollectionSchnittstelle implementieren .
Thorkil Holm-Jacobsen
9

Denken Sie daran, dass es die List.Count- Eigenschaft und dann die Enumerable.Count- Methode gibt.

In Ihrem Beispiel verwenden Sie die Enumerable.Count()Methode, die jedes einzelne Element der Aufzählung durchlaufen muss, um ein Ergebnis zurückzugeben. Das ist deutlich langsamer als ein Aufruf, Any()der nur über das erste Element iterieren muss, falls es vorhanden ist.

BEARBEITEN:

In den Kommentaren wurde zu Recht darauf hingewiesen, dass die Enumerable.Count()Erweiterungsmethode nicht alle Elemente durchlaufen muss, wenn festgestellt wird, dass es sich bei der Aufzählung auch um eine handelt ICollection<T>. Im Fall von a macht die List<T>Verwendung der CountEigenschaft oder Methode also keinen Unterschied.

IEnumerable.Count- Quelle:

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}
sstan
quelle
Fair genug. Was ist dann mit der Verwendung der .Count-Eigenschaft? Wäre das nicht wesentlich schneller, vielleicht genauso schnell oder sogar noch schneller als der Aufruf von .Any ()?
Gil Sand
4
Mit a wird List<T>der Leistungsunterschied vernachlässigbar. Verwenden Sie also einfach das, was Sie bevorzugen. Bei anderen Arten von IEnumerables können Sie jedoch nur zwischen Count()(der Methode) wählen. Any()In diesem Fall ist dies Any()immer der eindeutige Gewinner für Ihren Anwendungsfall und sollte bevorzugt werden. Für das, was es wert ist, halte ich es für Any()gut lesbar und klar.
Sstan
@sstan ja, es sei denn, wenn die unzähligen in eine Kollision umgewandelt werden können, kann sie optimiert werden und es spielt keine Rolle.
Esben Skov Pedersen
2
Count()hat die gleiche Komplexität wie Countfür ICollections, da die Erweiterungsmethode dann die Eigenschaft verwendet, anstatt zu iterieren.
Thorkil Holm-Jacobsen
Linq-Erweiterungen sind für bekannte Schnittstellen optimiert - IList, ICollection. Die Performance-Diskussion hier ist völlig überflüssig, auch wenn es sich um ein Implementierungsdetail handelt
Gusdor,
6

Eine überraschende Frage - ich finde die Absicht list.Any(), viel klarer zu sein als die Absicht von list.Count()!=0.

Absicht bedeutet: Wenn Sie einen Code gelesen haben (und ihn nicht selbst geschrieben haben), ist es völlig offensichtlich, was der Programmierer erreichen möchte und warum er so geschrieben hat, wie er ist? Wenn ein häufiges Problem unnötig komplex gelöst wird, wird man sofort misstrauisch und fragt sich, warum der Entwickler nicht den einfachen Weg gewählt hat. Sie sehen den Code durch und versuchen festzustellen, ob Sie etwas verpasst haben. Sie haben Angst, den Code zu ändern, weil Sie befürchten, dass ein Nebeneffekt fehlt, der zu unerwarteten Problemen führen kann.

Die Absicht der Verwendung der Any()Methode ist völlig klar - Sie möchten wissen, ob die Liste Elemente enthält oder nicht.

Die Absicht des Ausdrucks Count()!=0dagegen ist für den Leser nicht offensichtlich. Es ist natürlich nicht schwer zu erkennen, dass der Ausdruck Ihnen sagt, ob die Liste leer ist oder nicht. Die Frage stellt sich, weil Sie es auf diese Weise schreiben, anstatt die Standardmethode zu verwenden. Warum benutzt du Count()explizit? Wenn Sie wirklich brauchen nur zu wissen , ob es irgendwelche Elemente in einer Liste, warum tun Sie zuerst die ganze Liste zählen möchten? Sobald Sie 1 erreicht haben, haben Sie bereits Ihre Antwort. Wenn die Quelle ein Iterator über eine große (möglicherweise unendliche) Sammlung war oder in SQL übersetzt wird, kann dies die Leistung erheblich verbessern. Vielleicht besteht die explizite Verwendung von Count () darin, eine verzögerte Abfrage zur Ausführung zu zwingen oder einen Iterator zu durchlaufen?

Aber die Quelle ist eigentlich ein List<T>Wo Count()ist O (1) und hat keine Nebenwirkungen. Aber wenn der Code von dieser Eigenschaft abhängt List<T>, warum dann nicht die Count-Eigenschaft verwenden, die deutlicher anzeigt, dass Sie eine O (1) -Operation ohne Nebenwirkungen erwarten?

Wie es geschrieben steht, list.Count()!=0tut es genau das Gleiche, list.Any()außer es ist unnötig komplexer und die Absicht ist unklar.

JacquesB
quelle
Ich lese beides als "Enthält die Liste irgendwelche Gegenstände?" Count()hat eine implizite Konvertierung, die ich vermeiden würde, aber es ist nicht unklar. Der Compiler kann es weg optimieren, was es nur zu einer unachtsamen Codierung macht.
Suncat2000
2

Vielleicht ist es nur das Wort? Anyist ein Adjektiv, das eigentlich gar nichts sagt. Wenn ich von Java komme, würde ich es so nennen, dass es isNonEmptyein Verb enthält. Ein SQL-Typ könnte es vorziehen EXISTS. Passt aber vielleicht Anyam besten in das C # -System.

Was auch immer das Wort Wahl sein mag, sobald Sie sich daran gewöhnt haben, muss es viel klarer sein. Würden Sie fragen, ob noch more than zeroBierflaschen übrig sind? Würden Sie erwarten, dass one or morePersonen mit der Zählung beginnen, bevor sie mit "Nein, gibt es nicht any" antworten ?

maaartinus
quelle
1
Der Name „any“ Sinn macht , wenn man es in Bezug auf LINQ denkt: Any()ist wirklich eine Abkürzung fürAny(o => true)
BlueRaja - Danny Pflughoeft
Normalerweise würde ich leer nicht verwenden, um zu beschreiben, ob eine Aufzählung irgendetwas aufzuzählen hat. Aber „gibt es jede Sache aufzuzählen“ scheint mir, und jedes Werk gegen jede Aufzählung natürlich.
Andy