如何在Ruby中生成一个随机的10位数字?

75

此外,我如何将其格式化为左侧用零填充的字符串?

23个回答

97

要生成数字,请使用表达式“10的10次方”作为rand函数的参数。

rand(10 ** 10)

要在数字前面填充零,您可以使用字符串格式运算符

'%010d' % rand(10 ** 10)

或者字符串的rjust方法

rand(10 ** 10).to_s.rjust(10,'0')  

1
我刚意识到使用这种方法仍然可能会得到 0000000000。有没有什么方法可以防止这种情况发生? - Tintin81
不正确,因为有时会返回比实际位数少1或2个数字。例如上面的252402199、12348208。请检查我的答案。 - Lalit Kumar Maurya

66

我想贡献一种我所知道的最简单的解决方案,这是一个相当不错的技巧。

rand.to_s[2..11] 
 => "5950281724"

2
唯一的问题是它会给你一个字符串,所以如果你真的需要一个数字,那么你就必须再次进行强制转换 - 这有点麻烦。 - DaveStephens
6
值得注意的是,它只能提供最多16位数字。 - drewish
1
这并不是推荐的做法。它的长度并不总是如预期,因为 rand 可能会返回一个低至 0.0 的浮点值,导致生成的字符串为 "0"。如果你想确认,请在 irb 中尝试运行 (0.0).to_s[2..11] - Eliot Sykes

40

这是生成一个包含10个数字的字符串的快速方法:

10.times.map{rand(10)}.join # => "3401487670"

第一个数字可能是零,这将导致一个九位数。 - George Yacoub
@GeorgeYacoub 我想OP希望最终得到一个零填充的字符串。 - steenslag
这确实满足了OP提出的所有要求 - 即使第一个数字是一个数字。 - Oskar Holmkratz
5
实现相同目的的更高效方式:Array.new(10) { rand(10) } - Zachary Wright

18

最直接的答案可能是

rand(1e9...1e10).to_i

需要使用to_i部分,因为1e91e10实际上是浮点数:

irb(main)> 1e9.class
=> Float

1
这比@NhatTan提出的两个基准测试示例都要快得多。puts Benchmark.measure{(1..1000000).map{rand(1e9...1e10).to_i}}实际上,我需要一个字符串作为我的最终结果,但即使在末尾添加.to_s仍然会产生更快的结果。puts Benchmark.measure{(1..1000000).map{rand(1e9...1e10).to_i.to_s}} - Steve Meisner
我刚试了一下,但是无论如何都没能观察到以0开头的情况,尽管它有固定长度。 10000.times.map{rand(1e9...1e10).to_i.to_s}.select!{|x| x.start_with?("0")} 返回 []。 - Oskar Holmkratz
1
@OskarHolmkratz 这段代码生成一个介于1000000000和9999999999之间的数字。 - art-solopov
1
这绝对是最好的答案。我甚至不知道还有“三个点”的变体,我一直都用两个点。太棒了。 - jeffdill2
成功生成了两百万个唯一的数字。我使用了SecureRandom,因为rand()在50万时停止唯一性。SecureRandom.random_number(1e9...1e10).to_s[0..15].tr('.', '').to_i - Kazu

12

不要使用rand.to_s[2..11].to_i

为什么?因为你可能得到以下内容:

rand.to_s[2..9] #=> "04890612"

然后:

"04890612".to_i #=> 4890612

请注意:

4890612.to_s.length #=> 7

这不是你预期的结果!

为了检查你自己代码中的错误,你可以用下面的方式进行包装,而不是使用.to_i

Integer(rand.to_s[2..9])

很快就会变成:

ArgumentError: invalid value for Integer(): "02939053"

所以最好坚持使用.center,但要记住:

rand(9) 

有时可能会给你0

为了防止这种情况:

rand(1..9)

这个函数将始终返回 1..9 范围内的某个值。

我很高兴我的测试效果不错,希望你也能避免破坏你的系统。


11

随机数生成

使用Kernel#rand方法:

rand(1_000_000_000..9_999_999_999) # => random 10-digits number

随机字符串生成

使用 times + map + join 组合:

10.times.map { rand(0..9) }.join # => random 10-digit string (may start with 0!)

带填充的数字转字符串

使用String#%方法:

"%010d" % 123348 # => "0000123348"

密码生成

使用 KeePass 密码生成器 库,它支持不同的模式来生成随机密码:

KeePass::Password.generate("d{10}") # => random 10-digit string (may start with 0!)

可以在这里找到KeePass模式的文档。


7
虽然这并未被提及,但一般情况下我们更倾向于使用Kernel#sprintf方法(或它在Powerpack库中的别名Kernel#format),而非String#%方法。这也被提到了Ruby Community Style Guide
当然,这个问题有很多不同的观点,但为了提供更多的见解:
@quackingduck回答中的语法应该是:
# considered bad
'%010d' % rand(10**10)

# considered good
sprintf('%010d', rand(10**10))

这种偏好的本质主要是由于百分号%的神秘性质。它本身并不具有很强的语义,如果没有任何额外的上下文,它可能会被误解为%取模运算符。

样式指南中的示例:

# bad
'%d %d' % [20, 10]
# => '20 10'

# good
sprintf('%d %d', 20, 10)
# => '20 10'

# good
sprintf('%{first} %{second}', first: 20, second: 10)
# => '20 10'

format('%d %d', 20, 10)
# => '20 10'

# good
format('%{first} %{second}', first: 20, second: 10)
# => '20 10'

为了充分发挥String#%的作用,我个人更喜欢使用操作符式的语法而非命令式的语法,就像你会使用your_array << 'foo'而非your_array.push('123')一样。
这只是说明社区的一个趋势,“最好”的选择取决于您自己的需求。
更多信息请参见此博客文章

6

最后,我使用了 Ruby 核心模块的 srand 方法。

srand.to_s.last(10)

相关文档在这里:Kernel#srand


4

这里有一个表达式,它将比quackingduck的示例少使用一个方法调用。

'%011d' % rand(1e10)

需要注意的是,1e10 是一个 Float 类型,而 Kernel#rand 函数会将其转换为整数类型 to_i,所以对于一些较大的值可能会出现不一致的情况。如果要更加精确地使用字面量,也可以这样做:

'%011d' % rand(10_000_000_000) # Note that underscores are ignored in integer literals

4

('%010d' % rand(0..9999999999)).to_s

或者

"#{'%010d' % rand(0..9999999999)}"

这段代码生成一个10位随机数的字符串。

1
这是一个非常好的解决方案,为什么没有更多的点赞呢? - equivalent8

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