跨实现确定性数组#shuffle
可以将随机数生成器传递给Array#shuffle
,使得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相同的随机数生成器,但这只是偶然的,不能保证。
为了实现一致的跨实现确定性shuffle,我想将自定义随机数生成器传递给Array#shuffle
。 我认为这样做很简单,但事实certificate这很复杂。
以下是我在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
inheritance了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]
对我来说,解决方案是两件事的组合:
-
找出随机API。 这只是
rand
。 -
实现我自己的shuffle,因为不同的Ruby实现不一致。
我使用了my_array.sort_by { @random_generator.rand }
。