Quelle est l'utilisation de .Any () dans une liste C # <>?

40

J'ai discuté avec des collègues, et nous ne pouvions pas comprendre ce que l'utilisation est .Anypour tout donné List<>, en C #.

Vous pouvez vérifier la validité d'un élément du tableau comme ci-dessous:

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

Qui est exactement le même que

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

et est beaucoup plus commun, lisible et clair sur l'intention de la ifdéclaration.

En fin de compte, nous étions coincés avec cette pensée:

.Any() peut être utilisé, fonctionnera tout aussi bien, mais est moins clair sur l'intention du programmeur, et dans ce cas, il ne devrait pas être utilisé.

Mais nous pensons que cela ne peut pas être juste; nous devons manquer quelque chose.

Sommes nous?

Gil Sand
la source
40
en quoi toute intention est-elle moins claire?
jk.
35
Je conteste votre affirmation qui Any()est moins claire: Any()me semble plus claire, surtout avec une condition lambda. Traduire le code en anglais dans ma tête if(MyList.Count(o => o > 10) > 0)devient "Le nombre d'éléments supérieur à 10 est-il supérieur à 0?" alors que if(MyList.Any(o => o > 10))devient "Y a-t-il des objets supérieurs à 10?"
BlueRaja - Danny Pflughoeft
3
@SargeBorsch - seulement si vous préférez nommer Heskel / fonctionnel, ce que la plupart des gens ne font pas.
Davor Ždralo
4
@ BlueRaja-DannyPflughoeft je suis d'accord. Je pense que tout est plus clair car cela élimine un nombre qui pourrait être considéré comme un nombre magique.
Andy
2
@SargeBorsch: Le SQL parallèle à Anyest Exists. Le nom Linq est probablement plus inspiré de Haskell et Python, qui ont également toutes les fonctions.
JacquesB

Réponses:

95

Gardez à l'esprit que Anycela ne fonctionne pas sur un List; il opère sur un IEnumerable, qui représente un type concret qui peut ou non avoir une Countpropriété. Il est vrai que ce n’est pas forcément la meilleure chose à utiliser sur un List, mais cela est très utile à la fin d’une requête LINQ. Et même plus utile que la version autonome est le remplacement qui prend un prédicat comme Where. Il n'y a rien de plus intégré Listqui soit aussi pratique ou expressif que la Anyméthode d'extension de prédicat .

De même, si vous utilisez Count()(la méthode d'extension LINQ pour IEnumerable) plutôt que Count(la propriété activée List), il peut être nécessaire d'énumérer la séquence entière s'il ne peut pas l'optimiser en détectant que votre type de données sous-jacent a une Countpropriété. . Si vous avez une longue séquence, cela peut avoir un impact notable sur les performances lorsque vous ne vous souciez pas vraiment du nombre, et que vous voulez simplement savoir s'il y a des éléments dans la collection.

Maçon Wheeler
la source
19
Cette. La performance mise à part, Any()avec un prédicat est plus expressif que de comparer le dépassement de Enumerable.Count()qui prend un prédicat avec 0.
Dan J
1
Je pense que cela explique les fondamentaux si clairement que cela explique au mieux la réponse.
Tarik
2
IMHO, Existsest aussi pratique et expressif que Any, avec un prédicat. Utiliser une Count != 0propriété sur un Listest plus normal que d’utiliser Any(). C'est juste une préférence personnelle. Je suis aussi passé par l'effort de changer _list_.Count()pour _list_.Countdans le code de mon groupe. Cela a fait une différence notable pour moi.
Suncat2000
55

Il y a une différence de temps d'exécution qui Count()peut être O (n) où Any()est O (1).

Signe
la source
15
Count()également ne s'arrêtera pas pour les itérateurs infinis, tandis que le Any()sera, puisqu'il suffit d'appeler MoveNext()une fois.
Jon Purdy
3
Succinct et précis, mais cela se lit plus comme un commentaire que comme une réponse. Les programmeurs préfèrent les réponses qui approfondissent le pourquoi et fournissent une mesure d’explication. Pensez à modifier votre réponse et à expliquer pourquoi O (1) pourrait être (est) important.
très bonne réponse vient d'apprendre que je devrais utiliser tout au lieu de compter == 0: d
MonsterMMORPG
4
Any(Func<T>)is O (n)
BlueRaja - Danny Pflughoeft
1
Dans le cas spécifique de List, les performances sont identiques car l'extension utilise la propriété. Vrai pour toutes les collections implémentant l' ICollectioninterface.
Thorkil Holm-Jacobsen
9

En fait, gardez à l'esprit qu'il existe la propriété List.Count , puis la méthode Enumerable.Count .

Dans votre exemple, vous utilisez la Enumerable.Count()méthode, qui doit parcourir chaque élément de l'énumération pour renvoyer un résultat. C’est clairement plus lent que d’appeler Any()qui ne doit parcourir que le premier élément, s’il existe.

MODIFIER:

Dans les commentaires, il a été souligné, à juste titre, que la Enumerable.Count()méthode d’extension n’a pas besoin de parcourir tous les éléments si elle détecte que l’énumérable est également un ICollection<T>. Donc, dans le cas d'un List<T>, utiliser la Countpropriété ou la méthode ne fait pas de différence.

Source IEnumerable.Count :

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
la source
C'est suffisant. Qu'en est-il de l'utilisation de la propriété .Count alors? cela ne rendrait-il pas la lecture beaucoup plus rapide, peut-être aussi rapide ou même plus rapide que d'appeler .Any ()?
Gil Sand
4
Avec un List<T>la différence de performance sera négligeable. Alors, utilisez ce que vous préférez. Mais pour les autres types de IEnumerables, vous ne pouvez choisir qu'entre Count()(la méthode) et Any(), et dans ce cas, Any()sera toujours le gagnant gagnant de votre cas d'utilisation et devrait être préféré. Pour ce que ça vaut, je pense que Any()c'est assez lisible et clair.
sstan le
@sstan oui sauf si le nominatif est convertible en une collention, il peut être optimisé et sans importance.
Esben Skov Pedersen
2
Count()a la même complexité que Countpour ICollections, puisque la méthode d’extension utilise alors la propriété au lieu d’itérer.
Thorkil Holm-Jacobsen
Les extensions Linq sont optimisées pour les interfaces connues - IList, ICollection. La discussion sur les performances ici est totalement redondante, même s'il s'agit d'un détail de la mise en œuvre
Gusdor
6

Une question surprenante - Je trouve l’intention d’ list.Any()être beaucoup plus claire que l’intention de list.Count()!=0.

Intention signifie: si vous lisez le code de quelqu'un (et que vous ne l'avez pas écrit vous-même), est-il tout à fait évident que le programmeur veut réaliser et pourquoi il est écrit comme il est? Si un problème courant est résolu de manière inutilement complexe, vous êtes immédiatement suspicieux et vous vous demandez pourquoi le développeur n'a pas utilisé la méthode la plus simple. Vous parcourez le code et essayez de voir si vous avez oublié quelque chose. Vous avez peur de modifier le code car vous craignez que certains effets indésirables ne vous fassent pas défaut et que vous risquez de provoquer des problèmes inattendus.

L'intention d'utiliser la Any()méthode est tout à fait claire - vous voulez savoir s'il y a des éléments dans la liste ou non.

L'intention de l'expression Count()!=0en revanche n'est pas évidente pour le lecteur. Bien entendu, il n’est pas difficile de voir que l’expression vous indique si la liste est vide ou non. Les questions se posent parce que vous écrivez de cette manière particulière plutôt que d'utiliser la méthode standard. Pourquoi utilisez-vous Count()explicitement? Si vous avez vraiment besoin de savoir s'il y a des éléments dans une liste, pourquoi voulez-vous d'abord compter toute la liste? Dès que vous atteignez 1, vous avez déjà votre réponse. Si la source était un itérateur d'une grande collection (peut-être infinie) ou si elle était traduite en SQL, cela pourrait faire une grande différence en termes de performances. Alors peut-être que l'utilisation explicite de Count () consiste à forcer une requête différée à s'exécuter ou à traverser un itérateur?

Mais la source est en fait un List<T>Count()est O (1) et n'a pas d'effets secondaires. Mais si le code s'appuie sur cette propriété de List<T>, alors pourquoi ne pas utiliser la Countpropriété-qui indique plus clairement que vous attendez une opération O (1) sans effets secondaires?

Comme il est écrit, list.Count()!=0fait exactement la même chose, list.Any()sauf que c'est inutilement plus complexe et que l'intention n'est pas claire.

JacquesB
la source
Je lis les deux comme, "la liste contient-elle des éléments?" Count()a une conversion implicite que je voudrais éviter d'utiliser, mais ce n'est pas flou. Le compilateur peut l'optimiser à distance, ce qui ne fait que coder sans précaution.
Suncat2000
2

Peut-être que c'est juste le mot? Anyest un adjectif, ne dit vraiment rien. Venant de Java, je l'appellerais isNonEmptyqui contient un verbe. Un gars de SQL pourrait préférer EXISTS. Mais peut-être Anyconvient-il mieux au système C #.

Quel que soit le mot choisi, une fois que vous vous y habiterez, il doit être plus clair. Souhaitez-vous demander "Est-ce qu'il more than zeroreste des bouteilles de bière"? Vous attendriez-vous à ce que des one or morepersonnes commencent à les compter avant de répondre «non, il n'y en a pas any»?

maaartinus
la source
1
Le nom "n'importe lequel" prend tout son sens quand on pense à LINQ: Any()c'est vraiment un raccourci pourAny(o => true)
BlueRaja - Danny Pflughoeft le
Normalement, je n’utiliserais pas vide pour décrire si un énumérable avait quelque chose à énumérer. Mais "y a-t-il quelque chose à énumérer" me semble naturel, et N'importe qui agit contre tout dénombrement.
Andy