LINQ + Foreach vs Foreach + If

I need to iterate over a list of objects, doing something only for objects with a boolean property set to true. I discuss this code

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

and this code

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

The first code is clearly cleaner, but I suspect that it will cycle through the list twice - once for the request and once for the foreach. It will not be a huge list, so I am not too worried about performance, but the idea of ​​a loop just touches me twice.

Question: Is there a clean / nice way to write this without a loop twice?

+53
c # foreach linq
Jan 30 2018-12-01T00:
source share
4 answers

John Skeet sometimes does a LINQ demo for live performances to explain how this works. Imagine you have three people on stage. On the left, we have one guy who has a shuffled deck of cards. In the middle, we have one guy who only passes on red cards, and on the right, we have a guy who wants cards.

The guy rightfully forces the guy in the middle. The guy in the middle deflates the guy on the left. The guy on his left hand is the guy in the middle of the map. If it is black, the guy in the middle throws him to the floor and shuts him up again until he receives a red card, which he then directs to the guy on the right. Then the guy rightly again forces the guy in the middle.

This continues until the guy on the left has no cards left.

The deck did not go from start to finish more than once. . However, both the guy on the left and the guy in the middle processed 52 cards, and the guy on the right hand 26 cards. There were only 52 + 52 + 26 operations on the cards, but the deck was only looped.

Your version of LINQ and the continue version are one and the same; if you have

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

then there are 52 operations that extract each card from the deck, 52 operations that verify that each card is black, and 26 operations that operate on the red card. The exact same thing.

+122
Jan 30 '12 at 23:29
source share

Most Linq statements, such as Where , are implemented to support lazy and lazy execution . In your example, the list will be repeated only once, because the enumerator behind IEnumerable returned by Where will list the list until it finds an element that matches the predicate, gives it and continues only when the next element is offered to it .

From a code point of view, I would prefer the option of using where, although it can be argued that you can declare local to parameters.Where(p => p.Condition) .

Jon Skeet Edulinq series is highly recommended, reading some bits of this should help you with understanding LINQ statements.

+35
Jan 30 2018-12-12T00:
source share

Actually, this is not a β€œdouble cycle”. The .Where uses deferred execution. In other words, virtually no work is done when you call .Where , but when you .Where over the result, it will .Where over the original list and skip only those items that match your condition. If you think about it in terms of how the code is executed, you are effectively doing this:

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

As a style, I personally prefer something more:

 var matchingParameters = parameters.Where(p => p.Condition); foreach(var parameter in matchingParameters) { } 
+26
Jan 30 '12 at 23:06
source share

I prefer this:

 theList.Where(itm => itm.Condition).ToList().ForEach(itmFE => { itmFe.DoSomething(); }); 
-2
Jun 12 2018-12-12T00:
source share



All Articles