数组。复制vs跳过并接受c#

数组。复制vs跳过并接受c#,c#,arrays,copy,skip,take,C#,Arrays,Copy,Skip,Take,我浏览了这个问题和一些类似的问题: 很多地方我读到的答案如下: 我想知道的是,为什么Skip和Take不是数组的常量时间操作 反过来,如果它们是固定时间操作,Skip和Take方法(在最后不调用ToArray()的情况下)不会有相同的运行时间,而不会有执行数组的开销。复制,但也更节省空间?您必须区分Skip和Take方法所做的工作,以及使用方法返回的数据的工作 Skip和Take方法本身就是O(1)操作,因为它们所做的工作不随输入大小而缩放。他们只是设置了一个枚举器,可以从数组中返回项 当您

我浏览了这个问题和一些类似的问题:

很多地方我读到的答案如下:

我想知道的是,为什么Skip和Take不是数组的常量时间操作


反过来,如果它们是固定时间操作,Skip和Take方法(在最后不调用ToArray()的情况下)不会有相同的运行时间,而不会有执行数组的开销。复制,但也更节省空间?

您必须区分
Skip
Take
方法所做的工作,以及使用方法返回的数据的工作

Skip
Take
方法本身就是O(1)操作,因为它们所做的工作不随输入大小而缩放。他们只是设置了一个枚举器,可以从数组中返回项

当您使用枚举器时,工作就完成了。这是一个O(n)操作,其中n是枚举数产生的项数。当枚举器从数组中读取数据时,它们不包含数据的副本,并且只要使用枚举器,就必须保持数组中的数据完好无损


(如果对索引无法访问的集合(如数组)使用
Skip
,则获取第一项是一个O(n)操作,其中n是跳过的项数。)

考虑到您正在研究这些内容,这里有一个有用的小贴士:
Buffer.BlockCopy
(DMA)比
array.Copy
(O(n))非常快-但它只适用于原语(int、float等)。这并不能帮助我准确了解我所看到的内容,因为我使用的是对象数组,但知道这一点肯定很好,谢谢。使用Skip和Take枚举数组的效率并不低于枚举数组的副本,对吗?跳过和执行的评估是恒定时间。仅供参考,在我的用例中,引用的数组保持不变。@Rob Hinchliff:这两种方法都有开销。如果您复制阵列,您将在复制过程中获得开销,但您将获得循环阵列的全部好处,即可以优化访问阵列时的范围检查。使用枚举器时,开销在枚举器的代码中,即访问每个项所需的时间稍长。枚举器的真正好处是,您不必在内存中保留数组的副本,这对于大型数组来说只是一个问题。枚举Take()返回的集合的额外成本在哪里?是否类似于每次迭代都需要检查当前索引是否高于作为参数传递给Take()的计数?如果是这样的话,为什么不以与复制的数组相同的方式对其进行优化,因为范围检查也可以在这里提前完成?@Rob Hinchliff:开销主要在于返回的不是集合,而是枚举器。该代码调用枚举器的
MoveNext
方法和
Current
属性,并且不能像访问循环中的数组那样进行优化。因此,一个数组访问对应于两个方法调用,虽然这不是很多工作,但它远远不止是直接访问数组。这是因为编译器看不到底层集合实际上是Take()返回的IEnumerable接口后面的数组吗?我想我希望Take()返回的对象可能会有一些元数据,或者一些能够说服运行时使用数组循环的东西。