Ruby - 在一个数组中选取一个元素,有50%的几率获得[0],有25%的几率获得[1]

时间:2011-05-14 19:46:52

标签: ruby probability

没有什么太复杂,基本上我只是想从数组中选择一个元素,好像我正在为每个索引进行硬币抛出,并在我第一次得到头时选择索引。也没有头意味着我选择了最后一个垃圾箱。

我想出了以下内容,并想知道是否有更好/更有效的方法。

def coin_toss(size)
  random_number = rand(2**size)
  if random_number == 0
    return size-1
  else
    return (0..size-1).detect { |n| random_number[n] == 1 }
  end
end

2 个答案:

答案 0 :(得分:7)

首先猜测...在1和2**size之间选择一个随机数,找到其中的日志基数2,然后从最后选择许多元素的数字。

原谅我可怕的红宝石技巧。

return a[-((Math.log(rand(2**size-1)+1) / Math.log(2)).floor) - 1]

如果rand返回0,则应选择最后一个元素。 1或2,倒数第二。 3,4,5或6,从结束的第三个。等等。假设随机数的均匀分布,每个元素被选中的几率是后者的两倍。

编辑:实际上,似乎有一个log2函数,所以我们不必执行log / log(2)。

return a[-(Math.log2(rand(2**size - 1)+1).floor) - 1]

您可以完全摆脱这些日志调用,如

return a[-((rand(2**size-1)+1).to_s(2).length)]

但是你要创建一个额外的String。不确定这是否比复杂的数学更好。 :)

编辑:实际上,如果你要去字符串路线,你可以完全摆脱+1和-1。它使概率更准确,因为最后两个元素应该有相同的选择机会。 (如果未选择倒数第二个值,则最后一个值将始终为。)

编辑:我们也可以将**转变为一点移动,这应该快一点(除非Ruby已经足够聪明了)。

return a[-(rand(1<<size).to_s(2).length)]

答案 1 :(得分:5)

一种非智能,简单的方法是:

def coin_toss( arr )
  arr.detect{ rand(2) == 0 } || arr.last
end