数组#样本随机数生成器

zer*_*ro7 4 ruby

Array#sample如果你通过一个范围作为随机数发生器,如何工作?在这里:

> [*1..10].sample(random: 1..3)
=>9
Run Code Online (Sandbox Code Playgroud)

Aru*_*hit 6

根据文档,您可能不会想象sample(random: rng),rng它不是RangeObject.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
Run Code Online (Sandbox Code Playgroud)

关键是#sample,将其第二个参数作为关键字参数.如果我们使用类似foo: 12or的东西rng: (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
Run Code Online (Sandbox Code Playgroud)

当您传递第二个参数时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
Run Code Online (Sandbox Code Playgroud)

这会给你的理解有关#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]
Run Code Online (Sandbox Code Playgroud)

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