2012-01-30 65 views
53

我需要迭代對象列表,只爲布爾屬性設置爲true的對象執行某些操作。我這個代碼LINQ + Foreach vs Foreach +如果

foreach (RouteParameter parameter in parameters.Where(p => p.Condition)) 
{ //do something } 

和該代碼之間的辯論

foreach (RouteParameter parameter in parameters) 
{ 
    if !parameter.Condition 
    continue; 
    //do something 
} 

第一個代碼顯然是更清潔,但我懷疑它會遍歷列表中兩次 - 一次查詢和一次該foreach。這不會是一個巨大的名單,所以我不過分關注性能,但循環兩次的想法只是錯誤我。

問:有沒有乾淨/漂亮的方式來寫這沒有循環兩次?

+7

原來我誤解了LINQ的延遲執行的工作方式,而這些方式在實際執行相同。希望我可以標記多個答案,因爲下面的所有答案都會添加。 – Joel 2012-01-31 13:50:41

回答

122

喬恩斯基特有時會做一個實際的LINQ演示來解釋這是如何工作的。想象一下你有三個人在舞臺上。在左邊,我們有一個擁有一副牌的人。在中間,我們有一個只傳紅牌的人,而在右邊,我們有一個想要牌的人。

右側的傢伙捅中間的傢伙。中間的那個人捅了左邊的那個人。左邊的那個人把中間的那個人交給了一張牌。如果它是黑色的,那麼中間的人就會把它扔到地板上,然後再次捅出來,直到他拿到一張紅牌,然後他把手交給了右邊的那個人。然後,右邊的那個人再次捅了中間人。

這一直持續到左邊的傢伙用完卡片。

甲板從開始到結束都沒有經過多次。然而,左邊的人和中間的人都拿了52張牌,右邊的人拿了26張牌。牌上共有52 + 52 + 26次的戰鬥,但是的套牌只能通過

你的「LINQ」版本和「繼續」版本是一回事;如果你有

foreach(var card in deck) 
{ 
    if (card.IsBlack) continue; 
    ... use card ... 

則有52個操作,取指從甲板每張卡,52倍的操作是測試,看看每個卡是黑色的,和26個操作的紅牌上採取行動。完全一樣的東西。

+10

+1:不錯的背景*真人秀*例子! – 2012-01-30 23:50:32

+0

也許應該指出,保持這個列表不被列舉兩次並不神奇。在其他答案中提到了延期執行,因此請向這些人解釋爲什麼*它的工作方式與@Eric雄辯地描述的方式相同。 – hemp 2012-02-07 06:37:01

+0

真的很喜歡你解釋這個的方式。 – Tarik 2014-12-25 09:07:57

35

大多數Linq運營商如Where被實現爲支持延期執行和延遲執行。在你的例子中,這個列表只會遍歷一次,因爲位於由Where返回的IEnumerable後面的枚舉器將枚舉列表,直到它找到與謂詞相匹配的項爲止,併產生它,並且只有當它被請求下一個元素時纔會繼續。

從代碼的角度來看,我更喜歡使用where的變體,儘管可以聲稱你可以聲明本地的parameters.Where(p => p.Condition)

Jon Skeet的Edulinq系列強烈推薦,閱讀這些內容可以幫助您瞭解LINQ操作員。

26

實際上,它不是「循環兩次」。 .Where子句使用延期執行。換句話說,當您調用.Where時,實際上沒有任何工作會執行,但是當您遍歷結果時,它將迭代原始列表並僅傳遞符合條件的項目。如果你的代碼被執行方式方面想起來了,你有效地這樣做:

Func<Parameter, bool> matchesCondition = p => p.Condition; 
foreach(var parameter in parameters) 
{ 
    if(matchesCondition(parameter)) 
    { 
     ... 
    } 
} 

作爲一個風格問題,我個人更喜歡更多的東西一樣:

var matchingParameters = parameters.Where(p => p.Condition); 
foreach(var parameter in matchingParameters) 
{ 
} 
-2

我更喜歡這樣的:

theList.Where(itm => itm.Condition).ToList().ForEach(itmFE => { itmFe.DoSomething(); }); 
+8

這個*是*列舉了兩次。 OP *確實不需要*。 – 2012-07-20 12:27:03

+0

我想知道你爲什麼要那樣做。上面給出的答案是輝煌的 – Aakash 2013-08-07 09:53:15