数组#样本随机数生成器

时间:2015-02-23 19:16:44

标签: ruby

如果您将范围作为随机数生成器传递,Array#sample如何工作? 在这里:

> [*1..10].sample(random: 1..3)
=>9

1 个答案:

答案 0 :(得分:6)

根据文档sample(random: rng)rng不是Range对象,正如您可能想到的那样。 rng随机号码生成器。

  

可选的rng参数将用作随机数生成器。

a = (1..10).to_a
r = Random.new
r2 = r.dup
a1 = a.sample(random: r)
a2 = a.sample(random: r2)
a1 == a2 # => true

该点为#sample,将其第二个参数作为关键字参数。如果我们使用foo: 12rng: (1..2)之类的内容,则会提供 ArgumentError:unknown keyword:。只有当您为random: <any random number generator>提供值时,可选参数才可接受。现在,来到你的观点:

r = 1..3
a1 = [*1..10].sample(random: r)
a2 = [*1..10].sample(random: r)
a1 == a2 # => false

当您将第二个参数作为random: r传递时,r必须是Random个对象,或者是响应#rand对象。请记住,使用第二个参数,您告诉#sample,使用您的随机数生成器而不是默认它使用的默认缺少可选参数。

以下是 RNG 的一个自定义实现:

ob = Object.new

def ob.to_int
  5000
end

gen_to_int = proc do |max|
  ob
end

class << gen_to_int
  alias rand call
end

ary = (0...10000).to_a

ary.sample(random: gen_to_int) # => 5000
ary.sample(random: gen_to_int) # => 5000
ary.sample(random: gen_to_int) # => 5000

这将通过可选参数让您了解#sample。从#test_sample_random寻找更多示例。

<强>更新

  

如果您将范围作为随机数生成器传递,Array#sample如何工作?

要回答这个问题,我会接受TracePoint课程的帮助。

trace = TracePoint.new(:c_call) do |tp|
  p [tp.lineno, tp.defined_class, tp.method_id, tp.event]
end

trace.enable do
  [1,2,3,4,5,66,4].sample(random: 1..3)
end
# >> [6, Array, :sample, :c_call]
# >> [6, Kernel, :rand, :c_call]
# >> [6, Kernel, :respond_to_missing?, :c_call]

因此,从上面的调用堆栈,您可以看到 - Array#sample方法已被调用。现在在内部,Ruby在Kernel#rand对象上调用了Range。现在,(1..3).respond_to?返回false(因为#rand - 它是Range的a_private_实例方法),这就是为什么最后调用#respond_to_missing?方法的原因做这个工作。