【问题标题】:Array.Copy vs Skip and Take in c#Array.Copy vs Skip and Take in c#
【发布时间】:2011-11-13 15:23:57
【问题描述】:

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

Getting a sub-array from an existing array

我在很多地方读到这样的答案:

Getting a sub-array from an existing array

我想知道为什么 Skip 和 Take 不是数组的恒定时间操作?

反过来,如果它们是恒定时间操作,那么 Skip 和 Take 方法(没有在最后调用 ToArray() )是否具有相同的运行时间而没有执行 Array.Copy 的开销,而且还有更多空间有效率吗?

【问题讨论】:

  • 考虑到您正在研究这些东西,这是一个有用的花絮:Buffer.BlockCopy (DMA) 与 Array.Copy (O(n)) 相比 真的 快 - 它只是但适用于基元(int、float 等)。
  • 由于我使用的是对象数组,所以这对我正在查看的内容没有帮助,但知道这绝对是一件好事,谢谢。

标签: c# arrays copy skip take


【解决方案1】:

您必须区分SkipTake 方法所做的工作,以及使用这些方法返回的数据的工作。

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

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

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

【讨论】:

  • 使用 Skip 和 Take 枚举数组的效率不亚于枚举数组的副本,对吧? Skip 和 Take 的评估是常数时间。仅供参考,在我的用例中,引用的数组保持不变。
  • @Rob Hinchliff:这两种方法都有开销。如果您复制数组,则在复制过程中会产生开销,但是您将获得循环数组的全部好处,即可以优化访问数组时的范围检查。当您使用枚举器时,开销在枚举器的代码中,即访问每个项目需要稍长的时间。枚举器的真正好处是您不必在内存中保留数组的副本,这对于大型数组来说几乎是一个问题。
  • 枚举 Take() 返回的集合的额外成本在哪里?是否类似于每次迭代都需要检查当前索引是否高于作为参数传递给 Take() 的计数?如果是这样,为什么不以与复制数组相同的方式进行优化,因为范围检查也可以在这里完成?
  • @Rob Hinchliff:开销主要是返回的不是集合,而是枚举器。该代码调用了MoveNext 方法和枚举器的Current 属性,并且无法像在循环中访问数组一样进行优化。因此,一个数组访问对应于两个方法调用,虽然这不是很多工作,但它不仅仅是直接访问数组。
  • 这是因为编译器看不到底层集合实际上是Take()返回的IEnumerable接口后面的数组吗?我想我希望 Take() 返回的对象可能会有一些元数据或说服运行时使用数组循环的东西。
猜你喜欢
  • 2017-05-30
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多