71 votes

Différence entre IEnumerable Count() et Length

Quelles sont les principales différences entre IEnumerable Count() y Length ?

107voto

JaredPar Points 333733

En appelant Compte sur IEnumerable<T> Je suppose que vous faites référence à la méthode d'extension Count en System.Linq.Enumerable . Length n'est pas une méthode sur IEnumerable<T> mais plutôt une propriété sur les types de tableaux dans .Net tels que int[] .

La différence est la performance. Le site Length est garantie comme une opération O(1). La complexité de la Count La méthode d'extension diffère en fonction du type d'exécution de l'objet. Elle tentera d'effectuer un casting vers plusieurs types qui supportent la recherche de longueur O(1) comme ICollection<T> via un Count propriété. Si aucun n'est disponible, il énumérera tous les éléments et les comptera, ce qui a une complexité de O(N).

Par exemple

int[] list = CreateSomeList();
Console.WriteLine(list.Length);  // O(1)
IEnumerable<int> e1 = list;
Console.WriteLine(e1.Count()); // O(1) 
IEnumerable<int> e2 = list.Where(x => x <> 42);
Console.WriteLine(e2.Count()); // O(N)

La valeur e2 est implémenté comme un itérateur C# qui ne supporte pas le comptage O(1) et donc la méthode Count doit énumérer la collection entière pour déterminer sa longueur.

7 votes

List<T> n'a pas de propriété Length, mais une propriété Count. Les tableaux ont une propriété Length cependant. Count est spécifié dans ICollection y ICollection<T> (qui IList<T> s'étend).

0 votes

@JonSkeet et @Jared - Dans le contexte de l'analyse syntaxique d'une courte string[] avec disons 5-10 éléments... suggéreriez-vous de Array.Length pour la performance alors ?

1 votes

@one.beat.consumer : Ce serait toujours O(1) avec Count() car le tableau implémentera ICollection<T> - mais c'est moins efficace que d'utiliser Length directement. Si vous savez déjà que c'est un tableau, j'utiliserais Length no par souci d'efficacité, mais parce que je le considérerais comme plus idiomatique. De même, j'utiliserais le Count pour tout ce qui a un type de compilateur de ICollection<T> . J'appellerais Count() lorsque le expression de compilation est de type IEnumerable<T> même si je sais qu'il s'agit en fait d'un tableau en coulisse.

26voto

bniwredyc Points 4682

Petit plus pour Jon Skeet commentaire.

Voici le code source de la Count() méthode d'extension :

.NET 3 :

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    ICollection<TSource> is2 = source as ICollection<TSource>;
    if (is2 != null)
    {
        return is2.Count;
    }
    int num = 0;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            num++;
        }
    }
    return num;
}

.NET 4 :

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    ICollection<TSource> is2 = source as ICollection<TSource>;
    if (is2 != null)
    {
        return is2.Count;
    }
    ICollection is3 = source as ICollection;
    if (is3 != null)
    {
        return is3.Count;
    }
    int num = 0;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            num++;
        }
    }
    return num;
}

9 votes

Notez que dans .NET 4, il y a un autre bloc pour vérifier la présence de l'option non générique ICollection également. (Comme cela a aussi un Count propriété).

0 votes

Quelqu'un sait-il ce qu'il faut use pour obtenir le Error que cette méthode utilise ? Je ne la trouve nulle part sur MSDN, sauf dans la documentation JScript.

2voto

Erik Hart Points 187
  • La longueur est une propriété fixe, par exemple d'un tableau à une dimension ou d'une chaîne de caractères. Il n'y a donc jamais d'opération de comptage nécessaire (les tableaux multidimensionnels ont une taille de toutes les dimensions multipliées). L'opération O(1) signifie ici que le temps de récupération est toujours le même, quel que soit le nombre d'éléments. Une recherche linéaire serait (contrairement à cela) O(n).

  • La propriété Count sur les ICollections (List et List<T>, par exemple) peut changer, elle doit donc être mise à jour lors des opérations d'ajout/suppression, ou lorsque Count est demandé après que la Collection ait changé. Cela dépend de l'implémentation de l'objet.

  • La méthode Count() de LINQ itère en fait CHAQUE FOIS qu'elle est appelée (sauf lorsque l'objet est de type ICollection, auquel cas la propriété ICollection.Count est demandée).

Notez que les IEnumerables ne sont souvent pas des collections d'objets déjà définis (comme les listes, les tableaux, les hashtables, etc.), mais sont liés à des opérations en arrière-plan, qui génèrent des résultats dès qu'ils sont demandés (ce qu'on appelle l'exécution différée).

Typiquement, vous avez une déclaration SQL ou LINQ comme celle-ci (l'application typique de l'exécution différée) :

IEnumerable<Person> deptLeaders = 
   from p in persons
   join d in departments
      on p.ID equals d.LeaderID
   orderby p.LastName, p.FirstName
   select p;

Ensuite, il y a un code comme celui-ci :

if (deptLeaders.Count() > 0)
{
   ReportNumberOfDeptLeaders(deptLeaders.Count());
   if (deptLeaders.Count() > 20)
      WarnTooManyDepartmentLeaders(deptLeaders.Count());
}

Ainsi, lorsqu'un avertissement concernant un trop grand nombre de chefs de service est émis, .NET parcourt QUATRE fois les personnes, les compare aux chefs de service, les trie par nom, puis compte les objets résultants.

Et ce, uniquement lorsque les personnes et les départements sont des collections de valeurs prédéfinies, et non des requêtes elles-mêmes.

0 votes

Je pourrais ajouter que .Count() > 0 est la même chose que .Any() .

2 votes

@sfjedi : Je pense que ce n'est pas la même chose. Any() s'arrête quand un élément a été trouvé, alors que Count() itère sur tous. Donc quand on a un IEnumerable, possible pour une exécution différée, il faut préférer Any() pour une vérification à vide.

4 votes

N'est-ce pas ? .Any() être plus efficace que .Count() > 0 alors ? BTW, Resharper se plaint toujours de .Count() > 0 . C'est pourquoi je l'aborde avec confiance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X