Ruby 如何按指定概率从数组抽取元素?现有实现是否可行?
方案可行性判断
你提供的现有实现可以正常运行:rand(100)会生成0-99的随机整数,加1后范围为1-100,三个区间刚好对应5%、60%、35%的概率要求,适配你当前固定长度、固定概率的场景。
但该方案存在明显局限性:硬编码了数组下标和概率区间,后续如果需要调整概率、增减数组元素,都要手动修改case分支,可扩展性很差。另外方法中的p是打印语句,如果你不需要打印选中元素,直接删除p即可,不会影响方法的返回结果。
更优实现方案
通用兼容版(适配所有Ruby版本)
这个方案把权重和逻辑拆分,支持任意长度的数组、任意概率配置,不需要硬编码区间:
# arr:待抽取的数组,weights:对应每个元素的抽取权重 def weighted_sample(arr, weights) total_weight = weights.sum random_pick = rand(total_weight) arr.each_with_index do |item, index| random_pick -= weights[index] return item if random_pick < 0 end end # 你的场景使用示例 arr = [{:num=>1, :diff=>-29}, {:num=>2, :diff=>5}, {:num=>3, :diff=>25}] weights = [5, 60, 35] # 权重和为100刚好对应百分比概率 selected_item = weighted_sample(arr, weights) # 要添加到其他数组直接调用 push 即可:other_arr.push(selected_item)
极简原生版(适配Ruby 2.7及以上版本)
Ruby 2.7开始为数组的#sample方法内置了权重参数,直接调用原生方法即可,性能和稳定性更高:
arr = [{:num=>1, :diff=>-29}, {:num=>2, :diff=>5}, {:num=>3, :diff=>25}] selected_item = arr.sample(weights: [5, 60, 35])
内容的提问来源于stack exchange,提问作者Rhona
相关产品推荐
相关产品推荐

