加权字母生成器

时间:2019-02-05 17:32:09

标签: arrays ruby function random hash

我正在开发一个创建混杂字母组的程序,为此,我正在创建2个加权字母生成器,一个用于辅音,一个用于元音。

目前,我有一个使用散列进行加权的加权数字生成器,我可以使用希望其返回的字母数调用字母选择函数(例如pick_vowel(3))

def pick_vowel(x)
  vowels = { A: 15, E: 21, I: 13, O: 13, U: 5 }
  v_choice = []
  vowels.map {|letter, number| number.times {v_choice << letter}}
  x.times {print v_choice.shuffle!.pop}
end

然后,想法是使用以下代码将结果字符串传递给给出一定长度的所有可能组合的函数:

def solver(vowel)
  puts (2..9).flat_map{|size| board.combination(size).map(&:join)}
end

但是当我传递字符串时,我收到以下错误消息(在这种情况下,x = 6):

in `block in solver': undefined method `combination' for 6:Integer (NoMethodError)

我想将输出字符串转换为数组,但据我所知,输出字符串中会出现一个整数,因此array方法将不适用于它。

如何防止输出的末尾包含整数?

2 个答案:

答案 0 :(得分:0)

问题在这里:

x.times {print v_choice.shuffle!.pop}

上面的命令打印值x次,并返回值x Integer#times就是这样。

相反,您需要:

x.times.map { v_choice.shuffle!.pop }

或者更好

v_choice.shuffle!.pop(x)

因为Array#pop接受参数。

答案 1 :(得分:0)

假设

vowels = { A: 5, E: 8, I: 4, O: 7, U: 3, Y: 1 }

我知道此哈希值是绘制关联键的权重。您首先构造(以另一种方式):

v_choice = vowels.flat_map { |k,v| [k]*v }
  #=> [:A, :A, :A, :A, :A,
  #    :E, :E, :E, :E, :E, :E, :E, :E,
  #    :I, :I, :I, :I,
  #    :O, :O, :O, :O, :O, :O, :O,
  #    :U, :U, :U,
  #    :Y] 

接下来执行

x.times {print v_choice.shuffle!.pop}    

假设第一次洗牌会产生以下结果:

v_choice
  #=> [:O, :O, :E, :U, :U, :O, :A, :E, :E, :E, :U, :I, :A, :I,
  #    :E, :A, :O, :O, :E, :E, :O, :A, :I, :A, :O, :E, :I, :Y] 

然后

print v_choice.pop

打印"Y",并从:Y中删除唯一的v_choice。因此,:Y(概率为1)将不再被随机抽取,这与它具有正权重的事实相矛盾。

如果vowels的值不是权重,而是元音的有限集合中的数字,则可以大大简化。计算v_choice之后,只需要写

puts v_choice.sample(x).join
  # EOOYEIIEOI

puts v_choice.shuffle[0,x].join
  # EOOUOEEIAE

现在让我们假设vowels的值确实是权重。那我们只需要写

x = 10
x.times { print v_choice.sample }
# OAEYEUAOAO

如果vowels的值较大,则v_choice相应地也较大。那会影响内存需求,但不会影响执行速度。如果内存需求昂贵(也许不太可能),则可以执行以下操作。

tot_wts = vowels.values.sum.to_f
  #=> 28.0
cum = 0
cum_dist = vowels.map do |v,wt|
  cum_wt = cum + wt/tot_wts
  cum = cum_wt
  [v, cum_wt]
end
  #=> [[:A, 0.17857142857142858],
  #    [:E, 0.4642857142857143],
  #    [:I, 0.6071428571428572],
  #    [:O, 0.8571428571428572],
  #    [:U, 0.9642857142857143],
  #    [:Y, 1.0]]

如果发生舍入错误,我们可以设置

cum_dist[-1][-1] = 1.0

然后我们可以由此生成加权样本。

x = 10
x.times do
  rn = rand
  print cum_dist.find { |_,cum| rn < cum }.first
end
# EAAOOEEIOA

注意我们不能写

print cum_dist.find { |_,cum| rand < cum }.first

因为rand返回的值将在find的范围内不断变化。

这种技术,即所谓的“逆变换方法”,通常用于在仿真模型中生成离散的随机变量。