Array#shuffle
シャッフルを決定論的にする乱数ジェネレーターを渡すことができます。
たとえば、MRI1.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]