Разница между IEnumerable Count () и длиной - PullRequest
58 голосов
/ 26 марта 2010

Каковы основные различия между IEnumerable Count() и Length?

Ответы [ 3 ]

85 голосов
/ 26 марта 2010

Вызывая Count на IEnumerable<T> Я предполагаю, что вы имеете в виду метод расширения Count на System.Linq.Enumerable. Length - это не метод для IEnumerable<T>, а свойство для типов массивов в .Net, таких как int[].

Разница заключается в производительности. Свойство Length гарантированно является операцией O (1). Сложность метода расширения Count отличается в зависимости от типа объекта во время выполнения. Он попытается привести к нескольким типам, которые поддерживают поиск длины O (1), например ICollection<T> через свойство Count. Если ни один из них не доступен, он будет перечислять все элементы и считать их со сложностью O (N).

Например

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)

Значение e2 реализовано как итератор C #, который не поддерживает подсчет O (1), и, следовательно, метод Count должен перечислить всю коллекцию, чтобы определить ее длину.

20 голосов
/ 26 марта 2010

Небольшое дополнение к комментарию Джона Скита .

Вот исходный код метода расширения 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;
}
1 голос
/ 14 августа 2011
  • Длина является фиксированным свойством, например, одномерного массива или строки. Таким образом, никогда не требуется операция подсчета (многомерные массивы имеют размер всех умноженных размеров). Операция O (1) здесь означает, что время поиска всегда одинаково, независимо от количества элементов. Линейный поиск (в противоположность этому) будет O (n).

  • Свойство Count в ICollections (например, List и List ) может измениться, поэтому его необходимо обновить при операциях добавления / удаления или при запросе Count после изменения коллекции. Зависит от реализации объекта.

  • Метод LINQ Count () в основном выполняет итерацию КАЖДЫЙ раз, когда он вызывается (кроме случаев, когда объект имеет тип ICollection, тогда запрашивается свойство ICollection.Count).

Обратите внимание, что IEnumerables часто не являются уже определенными коллекциями объектов (такими как списки, массивы, хеш-таблицы и т. Д.), Но связаны с фоновыми операциями, которые генерируют результаты всякий раз, когда они запрашиваются (это называется отложенным выполнением).

Как правило, у вас есть SQL-подобный оператор LINQ, подобный этому (типичное применение отложенного выполнения):

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

Тогда есть код, подобный этому:

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

Таким образом, когда выдается предупреждение для слишком большого числа руководителей департаментов, .NET проходит ЧЕТЫРЕ РАЗА по лицам, проверяет их по лидерам департаментов, сортирует их по имени и затем подсчитывает объекты результатов.

И это только в том случае, если сотрудники и отделы представляют собой наборы заданных значений, а не сами запросы.

...