跨实现确定性数组#shuffle

时间:2012-12-08 03:40:10

标签: ruby jruby rubinius

可以将随机数生成器传递给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。我认为这样做很简单,但事实证明这很复杂。

以下是我在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]

1 个答案:

答案 0 :(得分:0)

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

  1. 找出随机API。这只是rand

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

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