ruby - Array#sample 是否保证随机顺序?

标签 ruby random

它是只保证随机子集,还是随机顺序?

用例是使用 ('a'..'z').to_a.sample(8).join 生成一个 secret 字符串。我想知道我是否可以相信所有 26⋅25⋅24⋅23⋅22⋅21⋅20⋅19 种可能的结果都是同样可能的。

documentation说:

Choose [...] n random elements from the array.

The elements are chosen by using random and unique indices into the array in order to ensure that an element doesn't repeat itself unless the array already contained duplicate elements.

我看到三种可能的解释。例如对于 [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 .

最佳答案

我希望该方法的名称源自 samples are drawn without replacement 的方式在统计中。在这种情况下,被抽样的总体元素不一定是有序的,如果它们是有序的,则与抽样的方式无关。

解释无放回抽样的通常方法是从容器中随机抽取一定数量的球,抽取的每个球在抽取下一个球之前放在一边。球可以通过颜色或数字或其他方式来识别,但采样的结果并不反射(reflect)任何排序的概念。

请记住,方法sample 是在类Array 上定义的,但数组的元素不一定是有序的。例如,

[1, "1", :one, 1..2, { a: 1 }].sample(2) # => [{:a=>1}, :one]

显然,这个样本的元素是无法排序的。

可以想象,sample 可以构造成在样本元素具有可比性的情况下对其进行排序,但我想不出另一种 Ruby 方法具有这种行为。此外,实现起来会有问题。很容易确定 [1,2,3,4] 的元素是可比较的(使用 Integer#<=> ),但并不总是那么简单。例如,假设数组是

[1, 2.5, 3/2r, BigDecimal.new("2.1")]

这些元素实际上是可比较的([1, (3/2), 0.21e1, 2.5] 已排序),但 Ruby 必须做一些工作才能做出决定。我想如果元素不可比较,Ruby 可以尝试对样本进行排序并挽救异常,但这似乎有些牵强。

关于ruby - Array#sample 是否保证随机顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47600931/

相关文章:

ruby - Mechanize 解析错误

mysql - 获取随机行,但不使用 ORDER BY RAND() MariaDB

c++ - C++ 中的 srand() 作用域

ruby - 使用 Ruby 解析 JSON 对象时出错

ruby - file.each_line 只能调用一次

从 Ruby 中调用 C 代码——如何使用返回的指针?

c++ - 如何从 rand() 缩小数字?

python - 如何在循环中不断更新张量的值

c++ - 存储和重新加载随机数生成器状态

ruby-on-rails - Heroku 无法检测到 rake 任务(LoadError : cannot load such file -- rspec/core/rake_task)