【问题标题】:Scala: iterate over collection in random order without creating a copyScala:以随机顺序迭代集合而不创建副本
【发布时间】:2014-08-13 02:55:51
【问题描述】:

在 Scala 中是否有办法为不可变集合(例如 List 或 Vector)获取流/视图/迭代器,该集合将以随机顺序遍历集合?据我了解 Random.shuffle(coll) 创建一个副本,这不是一种节省内存的方式。 Random.shuffle(coll.view) (或 coll.stream 或 coll.iterator)是更好的方法吗?这是否会产生明显的 CPU 开销?还是有更合适的方式?

【问题讨论】:

  • 寻找(伪)随机数生成器,其中第一个 myVector.size 值是唯一的,而无需重新调整初始范围,到目前为止搜索无果...

标签: scala random collections iteration traversal


【解决方案1】:

洗牌算法需要在集合中随机移动,并且需要以某种方式记住过去的选择。不可变集合在随机访问时不是很快(O(n) 而不是O(1) 用于List,可以说是O(1) 用于Vector,但常数因子很大)。

相比之下,复制集合几乎总是明智的做法。

【讨论】:

  • 在(我的)内存比 CPU 更有价值的情况下,复制是不可接受的。所以我需要较少占用 CPU 的方法。 Random.shuffle(myVector.iterator) 是否复制整个向量?
  • @Uniqus 请参阅github.com/scala/scala/blob/v2.11.2/src/library/scala/util/… 中的第 108 行(已创建新的 ArrayBuffer)
  • @Uniqus - 如果你有足够的条目让另一组指针成为问题,我很确定你不想从 O(n) 的运行时开始遍历随机列表到O(n^2)。当n 很大时,O(n^2) 非常糟糕(秒 -> 周)。
  • 是的,存储过去的选择仍然会消耗内存(不是一次,而是随着时间的推移),所以它只会推迟一个潜在的问题。所以唯一可以接受的方法确实是复制。好吧,谢谢大家,问题得到了解答。
  • C++ 中有a (possible) solution,但我决定坚持复制。
【解决方案2】:

如果考虑到集合复制,请考虑将索引的Array 改组为感兴趣的Vector,例如这样,

val myVector: Vector[MyObject] = ...

val shuffledIdx = util.Random.shuffle(0 until myVector.size)

这会复制一系列Int,可能比专用对象更轻。那么

shuffledIdx.map { idx => task (myVector(idx)) }

以随机顺序迭代/映射myVector 中的每个项目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-30
    • 2012-09-30
    • 2013-12-10
    • 2017-02-16
    • 1970-01-01
    • 2020-09-18
    • 2014-12-16
    • 2015-04-28
    相关资源
    最近更新 更多