2015-10-14 103 views
0

我有我自己的類的對象,看起來像列表:
IEnumerable.Count()或ToList()計數

public class IFFundTypeFilter_ib 
{ 
    public string FundKey { get; set; } 
    public string FundValue { get; set; } 
    public bool IsDisabled { get; set; } 
} 

酒店IsDisabled被做查詢collection.Where(some condition)和計數匹配的數量設置對象。結果是IEnumarable<IFFundTypeFilter_ib>,它不包含屬性Count。我想知道,什麼會更快。

這一個:

collection.Where(somecondition).Count(); 

或者這一個:

collection.Where(someocondition).ToList().Count; 

收集可能包含幾個對象,但也可能包含,例如700,我要做出計數呼叫,並用兩次其他條件。在第一種情況下,我檢查FundKey是否等於某個鍵,而在第二種情況下,我是這樣做的,但我將其與其他鍵值進行比較。

+0

這完全取決於'collection'的實際內容。你也可以不計算兩次,而是存儲該數字。 – CodeCaster

+0

我不能因爲在第二個電話我會檢查其他情況。 –

+0

@CodeCaster什麼類型的收集在這裏並不重要。我想你忽略了問題所在。 –

回答

3

你問:

我不知道,你會更快。

每當你問你應該實際計時並找出答案。

我的目標是測試所有獲得的計數,這些變種:

var enumerable = Enumerable.Range(0, 1000000); 
var list = enumerable.ToList(); 

var methods = new Func<int>[] 
{ 
    () => list.Count, 
    () => enumerable.Count(), 
    () => list.Count(), 
    () => enumerable.ToList().Count(), 
    () => list.ToList().Count(), 
    () => enumerable.Select(x => x).Count(), 
    () => list.Select(x => x).Count(), 
    () => enumerable.Select(x => x).ToList().Count(), 
    () => list.Select(x => x).ToList().Count(), 
    () => enumerable.Where(x => x % 2 == 0).Count(), 
    () => list.Where(x => x % 2 == 0).Count(), 
    () => enumerable.Where(x => x % 2 == 0).ToList().Count(), 
    () => list.Where(x => x % 2 == 0).ToList().Count(), 
}; 

我的測試代碼明確每個運行的方法1000次,每個執行時間,一個Stopwatch措施,並忽略所有結果,其中垃圾收集發生。然後每個方法獲得平均執行時間。

var measurements = 
    methods 
     .Select((m, i) => i) 
     .ToDictionary(i => i, i => new List<double>()); 

for (var run = 0; run < 1000; run++) 
{ 
    for (var i = 0; i < methods.Length; i++) 
    { 
     var sw = Stopwatch.StartNew(); 
     var gccc0 = GC.CollectionCount(0); 
     var r = methods[i](); 
     var gccc1 = GC.CollectionCount(0); 
     sw.Stop(); 
     if (gccc1 == gccc0) 
     { 
      measurements[i].Add(sw.Elapsed.TotalMilliseconds); 
     } 
    } 
} 

var results = 
    measurements 
     .Select(x => new 
     { 
      index = x.Key, 
      count = x.Value.Count(), 
      average = x.Value.Average().ToString("0.000") 
     }); 

下面是結果(下令從最慢到最快):

+---------+-----------------------------------------------------------+ 
| average |       method       | 
+---------+-----------------------------------------------------------+ 
| 14.879 |() => enumerable.Select(x => x).ToList().Count(),   | 
| 14.188 |() => list.Select(x => x).ToList().Count(),    | 
| 10.849 |() => enumerable.Where(x => x % 2 == 0).ToList().Count(), | 
| 10.080 |() => enumerable.ToList().Count(),      | 
| 9.562 |() => enumerable.Select(x => x).Count(),     | 
| 8.799 |() => list.Where(x => x % 2 == 0).ToList().Count(),  | 
| 8.350 |() => enumerable.Where(x => x % 2 == 0).Count(),   | 
| 8.046 |() => list.Select(x => x).Count(),      | 
| 5.910 |() => list.Where(x => x % 2 == 0).Count(),    | 
| 4.085 |() => enumerable.Count(),         | 
| 1.133 |() => list.ToList().Count(),        | 
| 0.000 |() => list.Count,           | 
| 0.000 |() => list.Count(),          | 
+---------+-----------------------------------------------------------+ 

兩件事情出來是顯著這裏。

之一,具有內聯.ToList()任何方法比沒有它的等效顯著慢。

二,LINQ運算符采取的基礎類型的枚舉,在可能情況下,短切的計算的優勢。 enumerable.Count()list.Count()方法顯示了這一點。

還有就是list.Countlist.Count()電話沒有什麼區別。因此,關鍵比較在enumerable.Where(x => x % 2 == 0).Count()enumerable.Where(x => x % 2 == 0).ToList().Count()調用之間。由於後者包含額外的操作,我們預計需要更長的時間。它差不多2.5毫秒。

我不知道爲什麼你說你要調用兩次計數的代碼,但如果你做的是更好地建設名單。如果不只是在查詢後執行簡單的.Count()調用。

3

一般來說,實現一個列表的效率會更低。

此外,如果您使用兩個條件,則無法緩存結果或將查詢實現爲List

你應該只使用其中Count接受謂詞過載:

collection.Count(someocondition); 

由於@CodeCaster在評論中提到,它相當於collection.Where(condition).Count(),但更具有可讀性和簡潔。

+0

'Where(x).Count()'與Count(x)'相同。 – CodeCaster

+0

@CodeCaster上面的水會發生什麼事也很重要:) – Rotem

+0

那麼,如果你能解釋爲什麼在你的答案... – CodeCaster

2

使用它正是這樣

var count = collection.Where(somecondition).ToList().Count; 

沒有意義 - 填充名單只是爲了得到計數,因此使用IEnumerable<T>.Count()是這種情況下,適當的方式。

使用ToList將使意義的情況下,你做這樣的事情

var list = collection.Where(somecondition).ToList(); 
var count = list.Count; 
// do something else with the list