【问题标题】:Efficiency of flattening and collecting slices压扁和收集切片的效率
【发布时间】:2020-02-22 13:53:49
【问题描述】:

如果有人在Iterator<Item=&[T]> where T: Copy 上使用标准.flatten().collect::<Box<[T]>>(),这样做:

  • 执行单次分配;和
  • 使用memcpy 将每个项目复制到目的地

还是做一些效率较低的事情?

【问题讨论】:

  • 你的意思是.flatten().copied().collect::<Box<[T]>>()

标签: rust iterator slice flatten memory-efficient


【解决方案1】:

Box<[T]> 没有实现 FromIterator<&T>,所以我假设您的实际内部迭代器是产生拥有的 Ts 的东西。

FromIterator<T> 用于Box<[T]> forwards to Vec<T>,其中uses size_hint()lower + 1 个项目保留空间,并随着它的增长而重新分配(根据需要移动元素)。那么问题来了,Flatten<I>size_hint 返回什么?

Iterator::size_hintFlatten<I>forwards to the internal struct FlattenCompat<I>的实现,有点复杂,因为它支持双端迭代,但最终还是returns (0, None) if the outer iterator has not been advanced or exhausted

所以你的问题的答案是:它做一些效率较低的事情。也就是说,(除非您已经在迭代器上至少调用了一次nextnext_back)它会创建一个空的Vec<T> 并根据Vec 使用的任何增长策略逐步增长它(未指定,但@987654325 @)。

这不是人为的限制;它是Flatten 工作方式的基础。您可以预先计算扁平迭代器大小的唯一方法是耗尽外部迭代器并将所有内部size_hints 相加。这是一个坏主意,因为它并不总是有效(内部迭代器可能不会返回有用的size_hints),而且您还必须找到一种方法来在用尽外部迭代器后保留内部迭代器;通用迭代器适配器没有可接受的解决方案。

如果您对特定迭代器有所了解,可以知道最终大小应该是多少,您可以通过调用Vec::with_capacity 自己保留分配,并使用Extendflattened 迭代器中填充它,而不是使用collect

【讨论】:

  • 很棒的答案!我已经完全按照你在最后一段中的建议做了,但在审查时想知道扁平化和收集是否会是实现相同目标的更雄辩的方式;唉,我将原样离开。谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-08-28
  • 1970-01-01
  • 2012-09-03
  • 1970-01-01
  • 2022-12-11
  • 2018-10-05
  • 1970-01-01
  • 2015-01-15
相关资源
最近更新 更多