web-dev-qa-db-fra.com

Différence entre IEnumerable Count () et Length

Quelles sont les principales différences entre IEnumerableCount() et Length?

58
balalakshmi

En appelant Count on IEnumerable<T> Je suppose que vous faites référence à la méthode d'extension Count sur 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. La propriété Length est garantie d'être une opération O(1). La complexité de la méthode d'extension Count varie en fonction du type d'exécution de l'objet. Elle sera essayez de transtyper en plusieurs types qui prennent en charge O(1) recherche de longueur comme ICollection<T> via une propriété Count. 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 prend pas en charge le comptage O(1)) et donc la méthode Count doit énumérer la collection entière pour déterminer sa durée.

87
JaredPar

Petit ajout à Jon Skeet 's comment.

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

.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;
}
21
bniwredyc
  • La longueur est une propriété fixe, par ex. d'un tableau ou d'une chaîne unidimensionnelle. Il n'y a donc jamais d'opération de comptage nécessaire (les tableaux multidimensionnels ont une taille de toutes les dimensions multipliée). O(1) opération ici signifie que le temps de récupération est toujours le même, peu importe le nombre d'éléments. Une recherche linéaire serait (contrairement à cela) être O (n).

  • La propriété Count sur 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 la modification de la collection. Dépend de l'implémentation de l'objet.

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

Notez que IEnumerables ne sont souvent pas des collections d'objets déjà définies (comme des listes, des tableaux, des tables de hachage, etc.), mais des liens vers des opérations d'arrière-plan, qui génèrent des résultats chaque fois qu'elles sont demandées (appelées exécution différée).

En règle générale, vous avez une instruction SQL comme 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 du code comme celui-ci:

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

Ainsi, lorsqu'un avertissement pour trop de chefs de département est émis, .NET passe QUATRE FOIS par le biais des personnes, les compare aux chefs de département, les trie par nom, puis compte les objets de résultat.

Et ce n'est que lorsque les personnes et les services sont des collections de valeurs prédéfinies, pas des requêtes elles-mêmes.

1
Erik Hart