2010-03-26 54 views

回答

71

通過致電IEnumerable<T>計數我假設您指的是System.Linq.Enumerable上的擴展方法CountLength不是IEnumerable<T>上的方法,而是.Net中陣列類型的屬性,例如int[]

不同之處在於性能。 Length屬性保證是O(1)操作。 Count擴展方法的複雜性根據對象的運行時類型而有所不同。它將嘗試通過Count屬性投射到支持O(1)長度查找的若干類型,如ICollection<T>。如果沒有可用的,那麼它將枚舉所有項目並計數它們的複雜度爲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枚舉整個集合,以確定它是多久一個C#迭代器。

+2

'List '沒有Length屬性 - 它有一個Count屬性。數組雖然有一個「長度」。 「計數」在「ICollection」和「ICollection 」(其中IList 延伸)中指定。 – 2010-03-26 07:15:43

+0

@Jon,doh。在這裏要歸咎於睡眠不足。將更新 – JaredPar 2010-03-26 07:18:01

+4

如果您的'IEnumerable '是無限長的,'Count()'永遠不會返回... – 2010-03-26 08:05:27

18

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; 
} 
+6

請注意,在.NET 4中還有另一個塊來檢查非泛型'ICollection'類型。 (因爲它也有一個'Count'屬性。) – 2010-03-26 07:37:28

+0

@Jon Skeet:謝謝 – bniwredyc 2010-03-26 07:58:30

+0

有沒有人知道'使用'來得到這個方法使用的'Error'類?我似乎無法在MSDN上的任何地方找到它,除了JScript文檔。 – 2012-06-10 20:50:44

1
  • 長度是固定的屬性,例如的單維數組或字符串。因此,從不需要計數操作(多維數組的所有維度的大小都相乘)。這裏的O(1)操作意味着無論有多少元素,檢索時間總是相同的。線性搜索(與此相反)是O(n)。

  • 上ICollections Count屬性(列表和列表<牛逼>,例如)可以改變的,所以它要麼被上添加更新/刪除操作,或當收集起來之後要求的次數已經改變。取決於對象的實現。 (除了當對象是一個ICollection類型,然後ICollection.Count屬性被請求時)。LINQ的Count()方法基本上遍歷每一個被調用的時間(除非對象是ICollection類型,則ICollection.Count屬性被請求)。

注意IEnumerables往往不是已經定義的對象集合(如列表,數組,哈希表等),但鏈接後臺操作,無論何時都要求他們能產生結果(被稱爲延遲執行)。

通常情況下,你有一個像LINQ聲明是這樣的(延遲執行的典型應用)的SQL:

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通過這些人走過了四次,與部門領導進行覈對,按名稱對它們進行排序,然後對結果對象進行計數。

這隻有當個人和部門是預設值集合,而不是查詢本身。

+0

我可能會補充說'.Count()> 0'和'.Any()'是一樣的。 – jedmao 2012-01-09 23:03:25

+1

@sfjedi:我認爲這是不一樣的。當找到一個項目時,Any()停止,而Count()遍歷所有項目。因此,如果有一個IEnumerable,可能延遲執行,則Any()應該優先用於空檢查。 – 2012-02-09 16:15:35

+3

那麼'.Any()'比'.Count()> 0'更有效嗎?順便說一句,Resharper總是抱怨'.Count()> 0'。這就是爲什麼我自信地提起它。 – jedmao 2012-02-09 17:47:30

相關問題