【发布时间】:2017-12-01 20:21:23
【问题描述】:
它只保证一个随机子集,还是随机顺序?
用例是用('a'..'z').to_a.sample(8).join 生成一个秘密字符串。我想知道我是否可以相信所有 26⋅25⋅24⋅23⋅22⋅21⋅20⋅19 种可能的结果都同样可能。
从数组中选择 [...] n 个随机元素。
通过在数组中使用随机且唯一的索引来选择元素,以确保元素不会重复自身,除非数组已经包含重复元素。
我看到了三种可能的解释。例如[1, 2, 3].sample(2):
- 返回
[1, 2]、[1, 3]、[2, 1]、[2, 3]、[3, 1]或[3, 2],每个概率为1/6。当您选择一个随机元素作为第一个输出元素,然后选择另一个随机元素(从剩余的元素中)作为第二个输出元素时,这就是您得到的结果。 - 返回
[1, 2]、[1, 3]或[2, 3],每个概率为1/3。这就是您通过选择索引的子集然后遍历数组得到的结果,如果它们的索引在所选元素中,则收集元素。 - 这两者之间有些奇怪。例如返回
[1, 2]或[1, 3],每个概率为1/3,或[2, 3]或[3, 2],每个概率为1/6。
我测试了它,第一个解释是发生了什么。并且查看源代码,我也有这样的印象,那就是它通常所做的事情。但我担心我忽略了某些东西,或者这只是当前实现的副作用,并且它可能会在未来发生变化(或者在某些 Ruby 实现中已经不同)。我可以想象第二种解释/实现是有益的,要么是因为一个想要这样“稳定”的采样,要么是出于效率的原因。
我的第一个解释是它应该做的吗?我可以依靠结果不仅是随机子集而且还具有随机顺序吗?文档不应该更清楚地说明这一点吗?
这是我的带有统计数据的测试代码,如果你想自己尝试一下:
array = (1..3).to_a
n = 2
count = Hash.new(0)
(10**6).times do
count[array.sample(n)] += 1
end
puts "#{count.size} different samples occurred."
puts "Smallest was #{count.keys.min}, largest was #{count.keys.max}."
puts "Frequencies ranged from #{count.values.min} to #{count.values.max}."
例如输出:
6 different samples occurred.
Smallest was [1, 2], largest was [3, 2].
Frequencies ranged from 165698 to 167234.
编辑:我创建了一个Ruby issue。
【问题讨论】:
-
@engineersmnky Ruby 使用 Mersenne Twister,而不是 C 的
rand。