繁体   English   中英

在 foreach 语句中执行 LINQ 是否更有效?

[英]Is it more efficient to perform a LINQ in a foreach statement?

这些陈述做同样的事情吗?

var listA = someList.TakeWhile(predicate);
foreach(var item in listA)
{
    /// perform code here
}

相对...

foreach(var item in someList.TakeWhile(predicate))
{
    /// perform some code here
}

是先创建集合,然后迭代 O(N^2) 吗? 还是集合在创建 O(N) 时迭代?

@Jeremy Lakeman 在评论中提供了正确答案。

变量listA的类型在:

var listA = someList.TakeWhile(predicate);

IEnumerable<T> , T 是集合someList的单个元素的类型。 TakeWhile方法的签名清楚地表明了这一点:

public static System.Collections.Generic.IEnumerable<TSource> TakeWhile<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,int,bool> predicate);

可以在TakeWhile文档页面中看到。

声明IEnumerable<T>类型的变量不会枚举它。 要枚举IEnumerable ,您必须明确地进行操作,例如在foreach循环中枚举它,或者使用它来生成新的物化集合,例如ListDictionary等……通过调用.ToList()等方法.ToList()ToDictionary()等...

这在(例如) ToList文档中明确说明:

ToList<TSource>(IEnumerable<TSource>)方法强制立即进行查询评估并返回包含查询结果的List<T> 您可以将此方法附加到查询中,以获取查询结果的缓存副本。 ToArray具有类似的行为,但返回一个数组而不是List<T>

因此,在您的两个代码示例中,您构造的IEnumerable将在foreach循环中仅枚举一次。

另外:即使您在枚举之前已经实现了您的集合:

var listA = someList
    .TakeWhile(predicate)
    .ToList(); // Notice the .ToList() call that forces the enumeration.

foreach(var item in listA)
{
    /// perform code here
}

它仍然是 O(n) 操作,而不是 O(n^2)。 如果您从someList集合中获取 N 个元素,您将使用.ToList()调用枚举它们一次,并在foreach循环中枚举它们一次,总共 2 x N,而不是 N^2。

两种形式都是一样的。 根据 Microsoft 文档,在直接或通过 foreach 调用其GetEnumerator方法之前,查询 ( TakeWhile ) 不会执行。

在通过直接调用其GetEnumerator方法或使用 Visual C# 中的foreach或 Visual Basic 中的For Each枚举对象之前,不会执行此方法表示的查询。

资源

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM