Разница между IEnumerable Count() и Length
каковы основные различия между IEnumerable
Count()
и Length
?
3 ответа:
по телефону рассчитывать на
IEnumerable<T>
Я предполагаю, что вы имеете в виду метод расширенияCount
onSystem.Linq.Enumerable
.Length
- это не методIEnumerable<T>
но скорее свойство для типов массивов в .Net, таких какint[]
.разница в производительности. Элемент
Length
свойство гарантированно будет операцией O(1). СложностьCount
метод расширения зависит от типа времени выполнения объекта. Он попытается привести к нескольким типам, которые поддерживают O (1) length lookup какICollection<T>
через aCount
собственность. Если ни один из них не доступен, то он будет перечислять все элементы и подсчитывать их, которые имеют сложность 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
необходимо перечислить всю коллекцию, чтобы определить ее длину.
маленькое дополнение к Джон Скиткомментарий.
здесь код
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; }
длина-это фиксированное свойство, например, одномерного массива или строки. Таким образом, никогда не требуется операция подсчета (многомерные массивы имеют размер всех умноженных измерений). O (1) операция здесь означает, что время извлечения всегда одно и то же, независимо от того, сколько элементов есть. Линейный поиск был бы(в противоположность этому) O (n).
свойство Count в ICollections (List и List
, например) может измениться, поэтому оно имеет либо для обновления при операциях добавления/удаления или при запросе 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 проходит четыре раза через лиц, проверяет их против руководителей отделов, сортирует их по имени, а затем подсчитывает результирующие объекты.
и это только тогда, когда люди и отделы являются предустановленными коллекциями значений, а не сами запросы.