如何在Ruby中获取随机数

830

我该如何生成一个介于0n之间的随机数?


1
在编写 rand 代码之前使用 srand <some_number> 将会给你一个确定性的(即可重复的)伪随机序列,如果你需要的话。https://ruby-doc.org/core-2.5.6/Random.html#method-c-srand - Purplejacket
18个回答

993

使用rand(range)

根据Ruby随机数

如果您需要一个随机整数来模拟掷骰子,您可以使用:1 + rand(6)。掷骰子可以使用2 + rand(6) + rand(6)模拟。

最后,如果您只需要一个随机浮点数,请调用不带参数的rand


正如Marc-André Lafortune他下面的答案中提到的那样(请给他点赞),Ruby 1.9.2有它自己的Random(Marc-André本人帮助调试,因此该功能的目标为1.9.2)。

例如,在这个需要猜测10个数字的游戏中,您可以使用以下方式初始化:

10.times.map{ 20 + Random.rand(11) } 
#=> [26, 26, 22, 20, 30, 26, 23, 23, 25, 22]

注意:

这就是为什么Random.new.rand(20..30)的等效写法是20 + Random.rand(11),因为Random.rand(int)返回“大于等于零且小于参数的随机整数”。20..30包括30,我需要生成一个在0到11之间、不包括11的随机数。


2
这不是非常不像 Ruby 的风格吗?我以为在 Ruby 中一切都是对象,最少惊讶原则等等... - Dan Rosenstark
1
@yar:它有点"Perl风格"。现在Ruby有它自己的Random类(请参见我的答案)。 - Marc-André Lafortune
2
@VonC 哦 :) 抱歉如果我有点严厉,只是让我感到惊讶了。 - horseyguy
1
Random.rand实际上可以接受一个范围(从1.9.3开始支持)。 - Ajedi32
1
@DanRosenstark:8年后... method(:rand) 输出 #<Method: Object(Kernel)#rand>。所以 rand 是一个 Kernel 方法,可用于每个 Object。如果你感觉更好,可以调用 self.send(:rand, 0..10) - Eric Duminil
显示剩余6条评论

610

虽然你可以使用rand(42-10) + 10来获取1042之间的随机数(其中10包含在内,而42不包含在内),但自Ruby 1.9.3以来,有一种更好的方法,你可以调用:

rand(10...42) # => 13

通过引用我的backports gem,可用于所有版本的Ruby。

Ruby 1.9.2还引入了Random类,因此您可以创建自己的随机数生成器对象,并具有良好的API:

r = Random.new
r.rand(10...42) # => 22
r.bytes(3) # => "rnd"

Random类本身就是一个随机生成器,因此您可以直接调用:

Random.rand(10...42) # => same as rand(10...42)

关于 Random.new 的注释

在大多数情况下,最简单的方法是使用 randRandom.rand。每次想要随机数时创建一个新的随机生成器是一个非常糟糕的想法。如果这样做,你将得到初始种子算法的随机属性,与随机生成器本身的属性相比,这些属性是极差的。

如果你使用 Random.new,因此应该尽可能少地调用它,例如一次性地调用 MyApp::Random = Random.new,并在其他地方使用它。

以下情况下,Random.new 是有帮助的:

  • 你正在编写一个 gem,并且不想干扰主程序可能依赖的 rand/Random.rand 的顺序
  • 你想要分离可重现的随机数序列(例如每个线程一个)
  • 你想要能够保存和恢复可重现的随机数序列(Random 对象可以轻松地被序列化)

1
太棒了!+1。我已经完成了我的答案,以反映这个新功能(并提到你在Bug #3104中的贡献 ;) )。 - VonC
1
@yar:我的 backports gem 只是一组在 Ruby 1.8.7、1.9.1、1.9.2 中新增但已在 Ruby 中实现的方法集合。我使用 RubySpec 来确保结果与 Ruby 兼容。 - Marc-André Lafortune
@Juanda:实际上我的示例是分成两行的,因为每次调用Random.new都是一个可怕的想法。我已经编辑了我的回答。 - Marc-André Lafortune
5
Random.rand(10..42) 不起作用。Random.rand类方法不接受一个范围(Ruby 1.9.2p180)。 - horseyguy
1
@banister:哇,我一直以为新的API(rand with range、bytes等)可以直接通过Random对象使用。rand with range将在1.9.3中提供,我会提出一个功能请求来获取bytes。我已经编辑了我的答案。 - Marc-André Lafortune
显示剩余6条评论

48

如果你不仅需要一个数字,而且还需要十六进制或uuid,值得一提的是,在1.9.2+版本中,SecureRandom模块从ActiveSupport移植到了Ruby核心中。因此,无需完整的框架:

require 'securerandom'

p SecureRandom.random_number(100) #=> 15
p SecureRandom.random_number(100) #=> 88

p SecureRandom.random_number #=> 0.596506046187744
p SecureRandom.random_number #=> 0.350621695741409

p SecureRandom.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"

这里有文档:Ruby 1.9.3 - 模块:SecureRandom (lib/securerandom.rb)


如果您需要四位数的随机数呢? - onurozgurozkan
1
我猜测 SecureRandom.random_number(1000..9999) - JayTarka
1
SecureRandom.random_number() 不需要范围,因此不行。你可能想要类似 SecureRandom.random_number(10_000) (表示 0-9999) 或 SecureRandom.random_number(9_000)+1_000 (表示 1000-9999) 这样的东西。 - mwp
1
Random.rand(1000..9999) - Jesse Farmer

39

你可以使用rand方法生成随机数。传递给rand方法的参数应该是一个整数或者一个范围,并返回在该范围内对应的随机数:

rand(9)       # this generates a number between 0 to 8
rand(0 .. 9)  # this generates a number between 0 to 9
rand(1 .. 50) # this generates a number between 1 to 50
#rand(m .. n) # m is the start of the number range, n is the end of number range

我认为使用rand(1..6)比排名第一的答案中的rand(6)+1更清晰易懂。 - isomorphismes

22

好的,我明白了。显然有一个内置的(?)函数叫做rand:

rand(n + 1)

如果有人提供更详细的答案,我将把它标记为正确答案。

2
是的,它是内核模块中的内置功能。 - Christoph Schiessl

17

这个怎么样?

n = 3
(0..n).to_a.sample

3
需要注意的是,像这个解决方案提供的生成数字数组的方法在处理大范围时性能非常差,因为它的时间复杂度是O(n),而rand的时间复杂度是O(1)。 - Travis

15

回答该问题最简单的方法:

rand(0..n)

11

你可以简单地使用random_number

如果给出正整数n,则random_number返回一个整数:0 <= random_number < n。

像这样使用它:

any_number = SecureRandom.random_number(100) 

输出结果将是0到100之间的任意数字。


6

范围 = 10..50

rand(范围)

或者

范围.to_a.sample

或者

范围.to_a.shuffle(这将打乱整个数组,您可以从这个数组中选择第一个、最后一个或任何一个数字来选择随机数)


1
当样本很大时,range.to_a.sample 是一个糟糕的想法。 - Greg

6
rand(6)    #=> gives a random number between 0 and 6 inclusively 
rand(1..6) #=> gives a random number between 1 and 6 inclusively

请注意,range选项仅在较新的Ruby版本(我相信是1.9+)中可用。


我相信 range 选项仅在 ruby 1.9.3+ 版本中可用。至少在我尝试时,在 1.9.2 版本中无法使用。 - Batkins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接