2011-10-05 46 views
4

LINQ:使用IEnumerable.Count()或IList.Count基於下面的代碼更好的性能

var grouped = filters.GroupBy(p => p.PropertyName); 
       int numOfRowElements = grouped.Count(); 
    foreach (IGrouping<string, PropertyFilter> filter in grouped) 
       { 


        foreach (var propertyFilter in filter) 
        { 
         // do something 
        } 

       } 

,其中過濾器列表,我的理解是,調用IEnumerable.Count()強制查詢被執行。這個執行的結果存儲在分組變量中,然後在foreach循環中使用,或者foreach循環強制查詢再次執行?相反,這樣做會更好嗎?

var grouped = filters.GroupBy(p => p.PropertyName).ToList(); 
    int numOfRowElements = grouped.Count; 
    foreach (IGrouping<string, PropertyFilter> filter in grouped) 
       { 


        foreach (var propertyFilter in filter) 
        { 
         // do something 
        } 

       } 

TIA。

回答

5

如果底層數據源是IList<T>Enumerable.Count()將調用.Count財產作爲優化,所以沒有*的性能損失。如果不是,則會強制枚舉。仔細考慮這一點。

var someList = new List<int>(); 
var count = someList.Count(); // will use .Count property 
var count = someList.OrderBy(x => x).Count(); // will force enumeration 

在這個例子中,我只是在第二個語句中獲得列表的數量。第三,我正在訂購清單,然後纔算清點。排序列表返回一個序列,而不是一個列表。因此,Count()方法是而不是工作在IList<T>,但是IEnumerable<T>。在這種情況下,必須枚舉查詢來獲取結果,並且會產生隨之而來的任何成本(在這種情況下是訂購)。

鑑於此,在您的第一個片段中,您將枚舉兩次查詢。一旦得到數據,就有一次這樣。這將執行所有的邏輯來將數據分組兩次。你的第二個例子只執行一次分組操作,而顯然在foreach中遍歷結果列表,這應該比第二次執行分組操作更便宜。 (是否可以測量一個儲蓄將完全取決於尺寸和/或在原始列表中的數據的源。有疑問時,輪廓它。)


*可能有測量罰對於間接層而言,如果您認爲這是一個真正的瓶頸,那麼您必須對此進行描述。但想想Count()方法爲

if (sequence is IList<T>) 
{ 
    return ((IList<T>)sequence).Count 
} 
else 
{ 
    /* perform enumeration */; 
} 
+0

感謝您的徹底迴應。原始列表中的數據大小不會很大,但是此操作將在UI線程上執行很多。 –

相關問題