ruby - 将自定义随机数生成器与 Ruby Array#shuffle/sample 一起使用

标签 ruby

当使用 Array#shuffle 时,Ruby 允许使用自定义随机发生器,甚至提供类 Random 来使用它。以下示例使用种子值为 48 的类。

array = [1,2,3,4,5,6,7,8,9,10]
array.shuffle(random: Random.new(48))  # => [8,6,3,7,10,9,5,2,4,1] 

我写了一个小的单位测试来查看一个值在打乱后的数组中首先出现了多少次。

deck = (1..10).to_a
counts = Hash.new(0)

rng = Random.new

50000.times do
  counts[deck.shuffle(random: rng).first] += 1
end

1.upto(10) do |card|
  puts "#{card}:\t#{counts[card]}"
end

输出类似于以下内容:

1:  4942
2:  5100
3:  4938
4:  4960
5:  5024
6:  4992
7:  5184
8:  4930
9:  4916
10: 5014

假设我想用一个新类替换伪随机数生成器。由于在上面的示例中 Array#shuffle 似乎使用了 Random#rand,因此实现一个新类作为随机数生成器进行洗牌似乎很简单。在这里,我实现了一个新的伪随机数生成器,它实际上只是 rand 的一个非常简单的包装器:

deck = (1..10).to_a
counts = Hash.new(0)

class FooRandom
  def rand(max=nil)
    max.nil? ? Kernel::rand : Kernel::rand(max)
  end
end

rng = FooRandom.new

50000.times do
  counts[deck.shuffle(random: rng).first] += 1
end

1.upto(10) do |card|
  puts "#{card}:\t#{counts[card]}"
end

然而,这并没有按预期运行。 FooRandom#rand 被调用,但洗牌产生以下分布:

1:  0
2:  5423
3:  5562
4:  5544
5:  5512
6:  5569
7:  5535
8:  5595
9:  5524
10: 5736

如您所见,在对数组进行打乱后,数组值 1 永远不会出现在数组的第一个位置。有人知道为什么吗?

最佳答案

有一个bug in Ruby 2.0.0p0限制偏离一个。

这已在 Ruby 2.0.0p195 中修复,因此您应该升级您的安装。

关于ruby - 将自定义随机数生成器与 Ruby Array#shuffle/sample 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16117548/

相关文章:

ruby - 太长时截断字符串

ruby - 绕过 Ruby 1. 9's new " native “线程”

mysql - 如何让 NetBeans 7.4、Ruby 和 MySQL 一起运行(在 Windows 上)

ruby-on-rails - 使用RAW Json进行轮胎多重搜索

ruby-on-rails - Ruby Net::FTP,从 ftp.list() 中提取文件名

ruby - 安装 Gem 时出现 SSL 错误(在 MinGW64-MSys2 上)

css - 如何从 ruby​​ 中的这个标签中抓取字符串

ruby-on-rails - RoR - 在开发模式下不加载或请求任何 Assets

ruby - 从较小的短语重建原始句子?

ruby-on-rails - 如何在 Ruby 中创建自定义排序方法