C# LINQ + Foreach 与 Foreach + If

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9072126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 05:47:37  来源:igfitidea点击:

LINQ + Foreach vs Foreach + If

c#linqforeach

提问by Joel

I need to iterate over a List of objects, doing something only for the objects that have a boolean property set to true. I'm debating between this code

我需要遍历对象列表,只对布尔属性设置为 true 的对象执行某些操作。我正在争论这段代码

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 obviously cleaner, but I suspect it's going to loop over the list twice - once for the query and once for the foreach. This won't be a huge list so I'm not overly concerned about performance, but the idea of looping twice just bugsme.

第一个代码显然更简洁,但我怀疑它会遍历列表两次 - 一次用于查询,一次用于 foreach。这会不会是一个巨大的名单,所以我不是太关心性能,但两次循环刚的想法的错误我。

Question: Is there a clean/pretty way to write this without looping twice?

问题:有没有一种干净/漂亮的方法来编写它而不循环两次?

采纳答案by Eric Lippert

Jon Skeet sometimes does a live-action LINQ demo 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 along red cards, and on the right, we have a guy who wants cards.

Jon Skeet 有时会做一个真人 LINQ 演示来解释它是如何工作的。想象一下你在舞台上有三个人。在左边我们有一个人,他有一副洗好的牌。在中间,我们有一个只会传红牌的人,而在右边,我们有一个想要红牌的人。

The guy on the right pokes the guy in the middle. The guy in the middle pokes the guy on the left. The guy on the left hands the guy in the middle a card. If it is black, the guy in the middle throws it on the floor and pokes again until he gets a red card, which he then hands to the guy on the right. Then the guy on the right pokes the guy in the middle again.

右边的人戳了中间的人。中间的人戳左边的人。左边的人给中间的人一张牌。如果是黑色,中间的人将它扔在地板上并再次戳,直到他得到一张红牌,然后将其交给右边的人。然后右边的人又戳了中间的人。

This continues until the guy on the left runs out of cards.

这种情况一直持续到左边的人用完牌。

The deck was not gone through from start to finish more than once.However, both the guy on the left and the guy in the middle handled 52 cards, and the guy on the right handled 26 cards. There were a total of 52 + 52 + 26 operations on cards, but the deck was only looped through once.

甲板从头到尾经过不止一次。然而,左边的人和中间的人都处理了 52 张牌,右边的人处理了 26 张牌。总共有 52 + 52 + 26 次对卡片的操作,但甲板只循环了一次

Your "LINQ" version and the "continue" version are the same thing; if you had

你的“LINQ”版本和“继续”版本是一样的;如果你有

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

then there are 52 operations that fetch each card from the deck, 52 operations that test to see if each card is black, and 26 operations that act on the red card. Same thing exactly.

然后有 52 个操作从一副牌中取出每张卡片,52 个操作测试每张卡片是否是黑色的,以及 26 个操作对红色卡片起作用。完全一样。

回答by Johannes Rudolph

Most Linq operators such as Whereare implemented to support deferred and lazy execution. In your example, the list will be iterated over only once because the enumerator sitting behind the IEnumerable returned by Wherewill enumerate the list until it finds an item matching the predicate, yields it and will only continue when it is asked for the next element.

大多数 Linq 运算符(例如)Where都被实现来支持延迟执行和延迟执行。在您的示例中,该列表将仅迭代一次,因为位于 IEnumerable 返回的枚举器后面的Where枚举器将枚举该列表,直到它找到与谓词匹配的项目,产生它,并且只有在它被要求提供下一个元素时才会继续。

From a code perspective, I'd prefer the variant using where, although it could be argued you could declare a local for parameters.Where(p => p.Condition).

从代码的角度来看,我更喜欢使用 where 的变体,尽管有人认为您可以为parameters.Where(p => p.Condition).

Jon Skeet's Edulinqseries comes highly recommended, reading some bits of this should help you with your understanding of LINQ operators.

强烈推荐Jon Skeet 的Edulinq系列,阅读其中的一些内容应该有助于您理解 LINQ 运算符。

回答by StriplingWarrior

Actually, it's not "looping twice." The .Whereclause uses deferred execution. In other words, practically no work is performed when you call .Where, but when you iterate over the result, it will iterate over the original list and only pass through items that match your condition. If you think of it in terms of how the code gets executed, you're effectively doing this:

实际上,它不是“循环两次”。该.Where子句使用延迟执行。换句话说,当您调用 时几乎不执行任何工作.Where,但是当您迭代结果时,它将迭代原始列表并且只传递与您的条件匹配的项目。如果您从代码的执行方式来考虑它,那么您实际上是在这样做:

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

As a matter of style, I personally prefer something more like:

就风格而言,我个人更喜欢以下内容:

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

回答by Carlos V

I prefer this:

我更喜欢这个:

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