Ruby
Car*_*and 5
Your code is fine but here are two other approaches.
Use a cumulative distribution function ("CDF")
CDF = [[0.05,0], [0.05+0.60,1], [0.5+0.60+0.35,2]] #=> [[0.05,0], [0.65,1], [1.0,2]]def get_num(arr) n = rand arr[CDF.find { |mx,_idx| n <= mx }.last]end arr = [{:num=>1, :diff=>-29}, {:num=>2, :diff=>5}, {:num=>3, :diff=>25}] get_num(arr) #=> {:num=>2, :diff=>5}get_num(arr) #=> {:num=>2, :diff=>5}get_num(arr) #=> {:num=>3, :diff=>25}get_num(arr) #=> {:num=>1, :diff=>-29}get_num(arr) #=> {:num=>2, :diff=>5}Suppose:
n = rand #=> 0.5385005480168696then
a = CDF.find { |mx,_idx| n <= mx } #=> [0.65,1]i = a.last #=> 1arr[i] #=> {:num=>2, :diff=>5}Note that I've followed the convention of beginning the name of find's second block variable (_idx) with an underscore to signal to the reader that that block variable is not used in the block calculation. Often just an underscore (_) is used.
Now consider the fraction of times each element of arr will be randomly-drawn if n draws are made:
def oute_fractions(arr, n) n.times .with_object(Hash.new(0)) { |_,h| h[get_num(arr)] += 1 } .transform_values { |v| v.fdiv(n) }endRandomly select from an array of indices
oute_fractions(arr, 1_000) #=> {{:num=>2, :diff=>5} =>0.612, # {:num=>3, :diff=>25} =>0.328, # {:num=>1, :diff=>-29}=>0.06}oute_fractions(arr, 100_000) #=> {{:num=>3, :diff=>25} =>0.34818, # {:num=>1, :diff=>-29}=>0.04958, # {:num=>2, :diff=>5} =>0.60224}Notice that the fraction of each hash that is randomly drawn approaches its specified population probability as the sample size is increased (though the "pseudo-random" draws are not truly random).
Do not be concerned with how oute_fractions works.
这是另一种更有效的方法(因为它不使用find,它执行线性搜索)但使用更多内存。
CHOICE = [*[0]*5, *[1]*60, *[2]*35] #=> [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # 2, 2, 2, 2, 2] def get_num(arr) arr[CHOICE[rand(100)]]end #=> {{:num=>2, :diff=>5} =>0.60029, # {:num=>3, :diff=>25}=>0.35022, # {:num=>1, :diff=>-29}=>0.04949}注意:
[*[0]*5, *[1]*60, *[2]*35]产生与
[[0]*5, [1]*60, [2]*35].flatten第一个是*splat运算符;第二个是方法Array#*。首先被评估。*[0]*5[0]*5 #=> [0,0,0,0,0]
CHOICE有 100 个元素。如果这三个概率是和0.048,则将具有元素(零、一和二)。0.6040.348CHOICE10**3 #=> 1_00048604348
Ruby