c# - LINQ 为什么 "Enumerable = Enumerable.Skip(N)"慢?

标签 c# linq ienumerable

我在 LINQ 查询的性能方面遇到问题,因此我创建了一个简化的小示例来演示下面的问题。该代码采用一个随机的小整数列表,并返回分成几个较小列表的列表,每个列表总计 10 个或更少。

问题是(正如我所写的那样)N 的代码花费的时间呈指数增长。这只是一个 O(N) 问题。 N=2500 时,代码在我的电脑上运行需要 10 多秒。

如果有人能解释发生了什么,我将不胜感激。谢谢,马克。

int N = 250;
Random r = new Random();
var work = Enumerable.Range(1,N).Select(x => r.Next(0, 6)).ToList();
var chunks = new List<List<int>>();

// work.Dump("All the work.");  // LINQPad Print
var workEnumerable = work.AsEnumerable();

Stopwatch sw = Stopwatch.StartNew();
while(workEnumerable.Any())  // or .FirstorDefault() != null
{
    int soFar = 0;
    var chunk = workEnumerable.TakeWhile( x => 
                          {
                              soFar += x;               
                              return  (soFar <= 10);
                          }).ToList();
    chunks.Add(chunk);          // Commented out makes no difference.
    workEnumerable = workEnumerable.Skip(chunk.Count); // <== SUSPECT
}
sw.Stop();

// chunks.Dump("Work Chunks.");   // LINQPad Print
sw.Elapsed.Dump("Time elapsed.");

最佳答案

.Skip() 所做的是创建一个新的 IEnumerable 循环遍历源,并且仅在第一个 N 之后开始产生结果元素。你把谁知道有多少这样的东西串联起来。每次调用 .Any() 时,都需要再次遍历之前跳过的所有元素。

一般来说,在 LINQ 中设置非常复杂的运算符链并重复枚举它们并不是一个好主意。此外,由于 LINQ 是一种查询 API,因此当您要实现的目标相当于修改数据结构时,Skip() 之类的方法是一个糟糕的选择。

关于c# - LINQ 为什么 "Enumerable = Enumerable.Skip(N)"慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13483672/

相关文章:

c# - EF 不要在 BindingSource 中使用 IQueryable 保存

c# - "System.Web.UI.MasterPage does not contain a definition..."ASP.NET 错误

c# - LINQ 链接中的 Any() 运算符

c# - 显式 IEnumerator<T> 实现 VS yield 返回实现

c# - HLSL:返回一个 float4 数组?

C# 使用强制转换将 Int64 转换为字符串

c# - 如果输入已经是列表,ToList 不会快捷方式

c# - LINQ C# 使用 2 个列表计算列表值

linq - 如何将 IQueryable 对象创建的表达式的执行转移到 IEnumerable?

linq - 处理 Azure 表批量更新的可靠且高效的方法