首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么`.Select(.).Last()`优化,但`.Select(.).Last(.)`没有?

为什么`.Select(.).Last()`优化,但`.Select(.).Last(.)`没有?
EN

Stack Overflow用户
提问于 2019-01-04 08:24:17
回答 1查看 324关注 0票数 15

考虑以下枚举数:

代码语言:javascript
复制
var items = (new int[] { 1, 2, 3, 4, 5 }).Select(x =>
{
    Console.WriteLine($"inspect {x}");
    return x;
});

这将产生元素[1, 2, 3, 4, 5],并在它们被消耗时打印它们。

当我在此枚举数上调用Last方法时,它会触发一个只访问单个元素的快速路径:

代码语言:javascript
复制
items.Last();
代码语言:javascript
复制
inspect 5

但是,当我将回调传递给Last时,它从一开始就循环遍历整个列表:

代码语言:javascript
复制
items.Last(x => true);
代码语言:javascript
复制
inspect 1
inspect 2
inspect 3
inspect 4
inspect 5

通过查看.NET核心源代码,我发现:

另一方面:

这解释了如何不优化回调情况。但这并不能解释原因。

从概念上讲,如果至少有一个元素满足谓词(这在实践中是可能的),那么向后迭代可能允许尽早退出循环。

它似乎也不难实现:据我所见,在IPartition<T>上只需要一个额外的方法。

缺乏优化也可能令人惊讶。由于这些重载具有相同的名称,因此可以假设它们也是以类似的方式进行优化的。(至少我是这么想的。)

考虑到优化这种情况的理由,为什么LINQ的作者选择不这样做?

EN

回答 1

Stack Overflow用户

发布于 2019-01-04 09:21:38

Last()始终可以针对允许在恒定时间内访问集合的最后一个元素(O(1))的集合进行优化。对于这些集合,您可以直接访问最后一个元素,而不是迭代所有集合并返回最后一个元素。

从概念上讲,如果至少有一个元素满足谓词(这在实践中是可能的),那么向后迭代可能允许尽早退出循环。

对于Last(Func<T,bool>)的一般实现来说,这种假设太过分了。您不能假设满足谓词的最后一个元素通常更接近集合的末尾。该优化对于您的示例(Last(x=>true))非常有效,但是对于每个这样的示例,都可能有一个优化执行更差(Last(x=>false))的oposite示例。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54035356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档