Разница между IEnumerable Count() и длиной - программирование
Подтвердить что ты не робот

Разница между IEnumerable Count() и длиной

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

4b9b3361

Ответ 1

Вызывая 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 реализовано как итератор С#, который не поддерживает подсчет O (1), и, следовательно, метод Count должен перечислять всю коллекцию, чтобы определить, сколько она времени.

Ответ 2

Небольшое дополнение к комментарию Jon Skeet.

Есть исходный код метода расширения 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;
}

Ответ 3

  • Длина является фиксированным свойством, например. одномерного массива или строки. Таким образом, никогда не требуется операция подсчета (многомерные массивы имеют размер всех измерений, умноженных). O (1) здесь означает, что время поиска всегда одно и то же, независимо от количества элементов. Линейный поиск был бы (напротив этого) O (n).

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

  • Метод Count() LINQ в основном выполняет итерацию КАЖДОГО ВРЕМЕНИ, которую он вызывается (кроме случаев, когда объект является типом 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 идет ЧЕТЫРЕХ ВРЕМЕНИ через людей, проверяет их против лидеров отдела, сортирует их по имени и затем подсчитывает объекты результатов.

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