我需要对对象列表进行迭代,只对布尔属性设置为true的对象执行一些操作。我在争论这段代码
foreach (RouteParameter parameter in parameters.Where(p => p.Condition))
{ //do something }这段代码
foreach (RouteParameter parameter in parameters)
{
if !parameter.Condition
continue;
//do something
}第一段代码显然更简洁,但我怀疑它将循环列表两次--一次用于查询,一次用于foreach。这不会是一个很大的列表,所以我不太关心性能,但循环两次的想法只是困扰我。
问:有没有一种干净的/漂亮的方法可以不用循环两次就写这篇文章?
发布于 2012-01-30 23:29:11
Jon有时会做一个实动LINQ演示来解释这是如何工作的。想象一下你有三个人在舞台上。在左边,我们有一个人,他有一副洗牌牌。在中间,我们有一个只传递红牌的人,在右边,我们有一个人想要红牌。
右边的那个人戳到中间的那个人。中间的那个人戳左边的那个人。左边的那个人,中间的那个人一张牌。如果是黑色的,中间的那个人把它扔到地板上,然后再戳,直到他得到一张红牌,然后他把红牌交给右边的那个人。然后右边的那个人又戳到了中间的那个人。
这种情况一直持续到左边的人没有牌了。
这副牌从开始到结束都没有超过一次,但是,左边的人和中间的那个人都处理了52张牌,右边的人处理了26张牌。总共有52 + 52 + 26次扑克牌,但这副牌只通过了一次。
您的"LINQ“版本和”继续“版本是相同的;如果您有
foreach(var card in deck)
{
if (card.IsBlack) continue;
... use card ...然后有52个操作,从甲板上取每一张卡,52个操作,测试每一张卡是否是黑色的,以及26个操作,作用在红牌上。同样的事情。
发布于 2012-01-30 23:04:50
大多数Linq操作符(如Where )都是为了支持延迟执行和延迟执行而实现的。在您的示例中,该列表将只迭代一次,因为位于IEnumerable返回的Where后面的枚举数将枚举该列表,直到它找到一个与谓词匹配的项,并生成它,并且只在请求下一个元素时才会继续。
从代码的角度来看,我更喜欢使用where的变体,尽管可以说您可以为parameters.Where(p => p.Condition)声明一个本地的。
Jon的艾德林系列非常推荐,阅读这方面的一些细节可以帮助您理解LINQ运算符。
发布于 2012-01-30 23:06: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)
{
}https://stackoverflow.com/questions/9072126
复制相似问题