DotnetDojo

Développer des applications modernes avec les technologies Microsoft et Open source

  • Blog
  • Vidéos
  • Formations
  • Outils

Faut-il utiliser Count ou Any ? Découvrez-le

Voici un article qui traite d’optimisation sur les traitements de données. Je vais vous présenter une technique qui n’est pas du tout évidente à première vue.

Habituellement, lorsque vous analysez des données, vous utilisez des listes ou des tableaux qui implémentent ICollection ou IEnumerable. Ces interfaces sont intéressantes car elles permettent d’utiliser des fonctionnalités puissantes dans .NET :

  • Si vous utilisez ICollection, vous pourrez accéder à la propriété Count pour connaître le nombre d’éléments dans la liste.
  • Si vous utilisez IEnumerable, vous pourrez utiliser l’opérateur foreach pour parcourir un ensemble d’éléments.
  • ICollection hérite de IEnumerable, donc toutes les collections peuvent être utilisées avec foreach.

L’objectif de cet article est de vous parler d’optimisation de code afin d’améliorer la vitesse d’exécution de votre application.

Pour vérifier si une liste est vide, je suppose que vous écrivez habituellement du code qui ressemble à ceci :
[csharp] if (maListe.Count == 0) {
/* traiter le cas de la liste vide */
}
[/csharp]

Récemment, en écrivant ce code, je me suis posé la question suivante : est-ce que Count est calculé à chaque fois ou bien est-ce que c’est une valeur qui est stockée ?

Comme expliqué précédemment, les types ICollection proposent une propriété Count qui stocke le nombre d’éléments. Donc, la valeur est connue.

Le problème vient très souvent de l’utilisation de la méthode d’extension Count() proposée par Linq.
La méthode Count() peut être utilisée sur des types plus larges comme les IEnumerables.

C’est là que peut survenir un problème de performance important :

  • Les types ICollection stockent le nombre d’éléments en interne. L’appel de .Count retourne ce nombre rapidement.
  • L’utilisation des méthodes d’extension Count() effectuent un calcul à chaque appel. Si vous avez un million d’éléments dans la liste, il faudra patienter un peu pour avoir le résultat.

Heureusement voilà, il existe une solution simple pour régler ce problème.

Linq propose également une méthode d’extension Any() qui retourne true si un IEnumerable contient au moins un élément.
Any() effectue une itération pour vérifier s’il y a au moins un élément dans un ensemble.

Any() est plus performant que de compter le nombre d’éléments puis de vérifier s’il est supérieur à zéro (Count > 0).

Any() semble donc être la solution. C’est aussi ce que je pensais jusqu’à ce que je regarde comment ça fonctionne « sous le capot » (grâce à la décompilation).

En réalité, .NET effectue une optimisation, on peut le voir dans la version décompilée :
[csharp] public static int Count<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw Error.ArgumentNull("source");

ICollection<TSource> collection1 = source as ICollection<TSource>;
if (collection1 != null)
return collection1.Count;

ICollection collection2 = source as ICollection;
if (collection2 != null)
return collection2.Count;

int num = 0;

using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
checked { ++num; }
}

return num;
}
[/csharp]

  • L’appel de Count vérifie si le type est compatible avec ICollection. Si oui, alors le framework appelle ICollection.Count, sinon il effectue une boucle pour calculer le nombre d’éléments.

Bilan

Je souhaitais simplement retenir votre attention sur les éléments suivants :

  • La méthode Any() existe et il est possible de l’utiliser. Si vous souhaitez savoir si un ensemble comporte au moins un élément, utilisez-là, elle est faite pour ça.
  • Pour des algorithmes qui utilisent ou vérifient le nombre d’éléments, préférez des types ICollection, le code sera toujours plus efficace.
  • Utilisez .Count ou Count() sur vos ensembles, sauf si vous êtes certain que le type est uniquement IEnumerable (et dans ce cas, utilisez Any() ).

Et vous, avez-vous des optimisations qui ressemblent à celles-ci ?

[ninja-inline id=3695]

Besoin de résultats rapides ?

Découvrez les formations vidéos que je propose :

  

 

Formations en présentiel (dans toute la France)

Découvrez également les formations C# et .NET que je donne en présentiel (en France)

Comments

  1. Invvard says

    17 juillet 2013 at 11 h 15 min

    Bien intéressant cet article, en particulier la partie sur l’optimisation réalisée sur l’utilisation du Count sur une ICollection.
    Les utilisateurs de Resharper le savent, celui-ci recommande lui aussi l’utilisation de Any() sur un IEnumerable.

    • Pascal Lacroix says

      17 juillet 2013 at 11 h 37 min

      Merci pour cette contribution.

      Effectivement, Resharper propose d’utiliser Any(). Et justement, là aussi il faut se demander si la liste d’éléments peut être du type ICollection ou pas.

  2. Pierre IRRMANN says

    17 juillet 2013 at 21 h 53 min

    Bonjour,
    Je ne suis pas d’accord du tout avec la conclusion de cet article. Les méthodes d’extension Any() et Count() de IEnumerable portent parfaitement leur noms : l’une est faite pour savoir si une séquence contient au moins un élément, l’autre pour connaitre le nombre d’éléments d’une séquence.
    Utiliser Count() pour savoir si une séquence contient au moins un élément, sous prétexte que l’on « sait » que l’IEnumerable est en réalité une Collection, est à mon sens un très mauvaise idée. Le gain de performance associé, s’il existe, doit être extrêmement petit. Dans toutes les situations, Any() reste un appel très peu coûteux, alors que Count() peut être très coûteux lorsque l’IEnumerable n’est pas une collection.
    « Mais puisque l’on sait que c’est une Collection », me direz-vous… Alors pourquoi est-ce que je manipule un IEnumerable et pas une collection alors ?

    • Pascal Lacroix says

      18 juillet 2013 at 16 h 13 min

      Merci Pierre de contribuer à la discussion.

      En fait, je pense que ma conclusion n’était pas assez claire. Je vais corriger ça.

      C’est certain que si on est sûr du type, il vaut mieux utiliser la bonne méthode d’extension.
      Je souhaitais simplement insister sur le fait que beaucoup de développeurs ne connaissent pas Any() et utilisent donc toujours « if Count> 0… ».

A propos de DotnetDojo

Pascal Lacroix

Je m’appelle Pascal et je suis passionné par le développement logiciel, l’efficacité et l’entrepreneuriat. Sur DotnetDojo, je vous propose des méthodes pour apprendre à développer des applications modernes avec les technologies Microsoft et Open Source.

En savoir plus

Liens complémentaires

  • A propos de DotnetDojo
  • 18 principes pour professionnaliser le développement logiciel
  • Boite à outils du développeur
  • Tous les articles
  • Liste des formations
  • Contact

Copyright 2019 Jupiteo · Mentions légales · Contact · CGV · Offres d'emploi .NET · Formations Dotnet