2012-12-08 31 views
1

可以將隨機數發生器傳遞給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] 

然而,沒有指定隨機的隨機數發生器實現。正因爲如此,Ruby的其他實現有不同的結果。

在Rubinius的2.0.0rc1(1.9.3版本2012年11月2日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告訴我,我需要實現的接口。

任何見解?


UPDATE:

作爲@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] 
+3

如果從'BasicObject'(而不是默認的'Object')繼承'NotRandom',會發生什麼? – glebm

+0

@glebm這會導致NoMethodError! –

+2

爲什麼你想要一個確定性的洗牌,以及一個確定性洗牌如何不同於一個簡單的有線硬連線列表? –

回答

0

對我來說,解決辦法是兩兩件事的組合:

  1. 找出隨機API。這只是rand

  2. 實現我自己的shuffle,因爲不同的Ruby實現不一致。

我用my_array.sort_by { @random_generator.rand }