LINQ + Foreach vs Foreach + If

Joe*_*oel 57 c# linq foreach

我需要迭代一个对象列表,只为布尔属性设置为true的对象做一些事情.我正在讨论这段代码

foreach (RouteParameter parameter in parameters.Where(p => p.Condition))
{ //do something }
Run Code Online (Sandbox Code Playgroud)

和这段代码

foreach (RouteParameter parameter in parameters)
{ 
  if !parameter.Condition
    continue;
  //do something
}
Run Code Online (Sandbox Code Playgroud)

第一个代码显然更干净,但我怀疑它会在列表上循环两次 - 一次用于查询,一次用于foreach.这会不会是一个巨大的名单,所以我不是太在意性能,但两次循环刚的想法的错误我.

问题:如果没有循环两次,是否有一种干净/漂亮的方式来编写它?

Eri*_*ert 130

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

右边的那个人在中间捅了那个家伙.中间的那个人捅了左边的那个人.左边的那个人把中间的那个人递给了一张牌.如果它是黑色的,那么中间的那个人把它扔在地板上然后再次戳,直到他得到一张红牌,然后他将牌递给右边的那个人.然后右边的那个人又把那个中间人捅了出来.

这种情况一直持续到左边的那个人用完纸牌.

甲板从头到尾不止一次经过.然而,左边的那个人和中间的那个人处理了52张牌,而右边的那个人处理了26张牌.卡上总共有52 + 52 + 26次操作,但是牌组只进行了一次.

你的"LINQ"版本和"继续"版本是一回事; 如果你有

foreach(var card in deck)
{
    if (card.IsBlack) continue;
    ... use card ...
Run Code Online (Sandbox Code Playgroud)

然后有52个操作从牌组中取出每张牌,52个操作测试每张牌是否为黑色,以及26个操作在红牌上.同样的事情.

  • +1:很棒的背景*真实动作*例子! (12认同)

Joh*_*lph 37

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

从代码的角度来看,我更喜欢使用where的变体,虽然可以说你可以声明一个local parameters.Where(p => p.Condition).

强烈建议使用Jon Skeet的Edulinq系列,阅读这些内容可以帮助您理解LINQ运算符.


Str*_*ior 27

实际上,它不是"循环两次".该.Where子句使用延迟执行.换句话说,实际上在调用时不会执行任何工作.Where,但是当您遍历结果时,它将遍历原始列表并仅传递符合您条件的项目.如果您根据代码的执行方式来考虑它,那么您实际上是这样做的:

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

作为一种风格问题,我个人更喜欢以下内容:

var matchingParameters = parameters.Where(p => p.Condition);
foreach(var parameter in matchingParameters)
{
}
Run Code Online (Sandbox Code Playgroud)