2010-03-26 17 views

उत्तर

71

IEnumerable<T> पर गिनती करके मुझे लगता है कि आप एक्सटेंशन विधि Count पर System.Linq.Enumerable पर संदर्भित कर रहे हैं। LengthIEnumerable<T> पर एक विधि नहीं है बल्कि सरणी प्रकारों पर एक संपत्ति है जैसे कि int[]

अंतर प्रदर्शन है। Length संपत्ति ओ (1) ऑपरेशन होने की गारंटी है। Count विस्तार विधि की जटिलता वस्तु के रनटाइम प्रकार के आधार पर भिन्न होती है। यह Count संपत्ति के माध्यम से ICollection<T> जैसे ओ (1) लंबाई लुकअप का समर्थन करने वाले कई प्रकारों को कास्ट करने का प्रयास करेगा। यदि कोई भी उपलब्ध नहीं है तो यह सभी वस्तुओं की गणना करेगा और उनको गिनेंगा जिनमें ओ (एन) की जटिलता है।

उदाहरण

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 के लिए एक सी # इटरेटर जो हे (1) गिनती का समर्थन नहीं करता है और इसलिए विधि Count निर्धारित करने के लिए कितना समय है पूरे संग्रह करके बताना चाहिए के रूप में कार्यान्वित किया जाता है।

+2

'सूची ' की लंबाई संपत्ति नहीं है - इसमें एक गणना संपत्ति है। हालांकि Arrays के पास 'लंबाई' है। 'गणना '' ICollection' और 'ICollection ' में निर्दिष्ट है (जो 'IList ' विस्तारित करता है)। –

+0

@ जोन, दोह। नींद की कमी को दोषी ठहराते हुए। – JaredPar

+4

अपडेट करेगा और यदि आपका 'आईनेमरेबल ' असीमित रूप से लंबा है, तो 'गणना() 'कभी वापस नहीं आएगी ... –

18

Jon Skeet की टिप्पणी के लिए थोड़ा सा अतिरिक्त।

नेट 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; 
} 

नेट 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 में गैर-सामान्य 'आईसीओलेक्शन' प्रकार की जांच करने के लिए एक और ब्लॉक भी है। (क्योंकि इसमें 'गणना' संपत्ति भी है।) –

+0

@ जोन स्कीट: धन्यवाद – bniwredyc

+0

क्या कोई यह जानता है कि इस विधि का उपयोग करने वाली 'त्रुटि' कक्षा प्राप्त करने के लिए 'उपयोग' का क्या अर्थ है? जेएसपी दस्तावेज को छोड़कर, मुझे इसे एमएसडीएन पर कहीं भी नहीं मिल रहा है। –

1
  • लंबाई है एक निश्चित संपत्ति है, उदा

    Count() विस्तार विधि के स्रोत कोड रहे हैं एक आयामी सरणी या स्ट्रिंग का। तो कभी भी एक गिनती ऑपरेशन आवश्यक नहीं है (बहु-आयामी सरणी में सभी आयामों का आकार गुणा होता है)। ओ (1) ऑपरेशन का मतलब है कि पुनर्प्राप्ति का समय हमेशा समान होता है, इससे कोई फर्क नहीं पड़ता कि कितने तत्व हैं। एक रैखिक खोज (इसका विरोध) ओ (एन) होगा।

  • ICollections पर गणना संपत्ति (सूची और सूची < टी >, उदाहरण के लिए), बदल सकते हैं तो यह या तो जोड़ें पर अद्यतन किया जाना है/संचालन निकाल दें, या जब गणना संग्रह के बाद अनुरोध किया जाता है बदल गया है। वस्तु के कार्यान्वयन पर निर्भर करता है।

  • LINQ की गणना() विधि मूल रूप से इसे हर बार पुनरावृत्त करती है (जब ऑब्जेक्ट एक आईसीलेक्शन प्रकार होता है, तो ICollection.Count प्रॉपर्टी का अनुरोध किया जाता है)।

ध्यान दें कि IEnumerables हैं बार नहीं पहले से ही वस्तु संग्रह (जैसे सूचियों, सरणियों, hashtables आदि) में परिभाषित किया गया है, लेकिन पृष्ठभूमि में कार्य है, जो परिणाम उत्पन्न जब भी वे अनुरोध कर रहे हैं के लिए लिंक (बुलाया आस्थगित निष्पादन)।

आमतौर पर, आप इस तरह 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 व्यक्तियों के माध्यम से चार बार जाता है, उन्हें विभाग के नेताओं के खिलाफ जांचता है, उन्हें नाम से टाइप करता है और फिर परिणाम वस्तुओं की गणना करता है।

और यह तब होता है जब व्यक्तियों और विभाग प्रीसेट मूल्य संग्रह होते हैं, स्वयं से पूछताछ नहीं करते हैं।

+0

मैं जोड़ सकता हूं कि '.Count()> 0' वही चीज़ है जैसे' कोई() '। – jedmao

+1

@ एसएफजेडी: मुझे लगता है कि यह वही नहीं है। कोई भी() बंद हो जाता है जब कोई आइटम पाया जाता है, जबकि गणना() सभी के माध्यम से पुनरावृत्त होती है। तो जब स्थगित निष्पादन के लिए संभव है, तो किसी भी() को खाली चेक के लिए प्राथमिकता दी जानी चाहिए। –

+3

'कोई()' 'गणना()> 0' से अधिक कुशल नहीं होगा? बीटीडब्ल्यू, रिशेर्पर हमेशा 'गणना()> 0' के बारे में शिकायत करता है। यही कारण है कि मैं इसे आत्मविश्वास से लाता हूं। – jedmao

संबंधित मुद्दे