【问题标题】:Cross-Implementation Deterministic Array#shuffle交叉实现确定性数组#shuffle
【发布时间】:2012-12-08 03:40:09
【问题描述】:

可以将随机数生成器传递给Array#shuffle,从而使随机播放具有确定性。

例如,在 MRI 1.9.3p327 中:

[1, 2, 3, 4].shuffle(random: Random.new(0)) # => [1, 2, 4, 3]
[1, 2, 3, 4].shuffle(random: Random.new(0)) # => [1, 2, 4, 3]

但是,没有指定 Random 的随机数生成器实现。因此,Ruby 的其他实现有不同的结果。

在 Rubinius 2.0.0rc1(1.9.3 发布 2012-11-02 JI)中:

[1, 2, 3, 4].shuffle(random: Random.new(0)) # => [1, 3, 2, 4]
[1, 2, 3, 4].shuffle(random: Random.new(0)) # => [1, 3, 2, 4]

顺便说一下,jruby-1.7.1 使用与 MRI 1.9.3p327 相同的随机数生成器,但这只是偶然,不能保证。

为了实现一致的跨实现确定性随机播放,我想将自定义随机数生成器传递给Array#shuffle。我以为这很简单,但结果却相当复杂。

这是我首先尝试的,在 MRI 中:

class NotRandom; end
[1, 2, 3, 4].shuffle(random: NotRandom.new) # => [4, 3, 2, 1]
[1, 2, 3, 4].shuffle(random: NotRandom.new) # => [4, 2, 1, 3]

我希望 NoMethodError 告诉我我需要实现的接口。

有什么见解吗?


更新:

正如@glebm 指出的那样,NotRandom 继承了Kernel#rand,这是需要的接口。这很容易解决,但遗憾的是没有提供解决方案。

class NotRandom
  def rand(*args)
    0
  end
end

在 RBX 中:

[1, 2, 3, 4].shuffle(random: NotRandom.new) # => [1, 2, 3, 4]

在 MRI 中:

[1, 2, 3, 4].shuffle(random: NotRandom.new) # => [2, 3, 4, 1]

【问题讨论】:

  • 如果你从BasicObject(而不是默认的Object)继承NotRandom会发生什么?
  • @glebm 这会导致 NoMethodError!
  • 为什么需要确定性随机播放?确定性随机播放与简单的硬连线排列列表有何不同?
  • @muistooshort 我想在测试上下文中进行确定性随机播放。我可以通过注入一个随机数生成器来实现这一点。在生产中,我会使用随机。在测试中,我会使用 NotRandom。
  • 您的测试不应该因为shuffle 是不确定的而失败。

标签: ruby jruby rubinius


【解决方案1】:

对我来说,解决方案是两件事的结合:

  1. 找出随机 API。只是rand

  2. 实现我自己的 shuffle,因为不同的 Ruby 实现不一致。

我使用了my_array.sort_by { @random_generator.rand }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-20
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    • 2017-11-13
    相关资源
    最近更新 更多