【问题标题】:How do I generate a random 10 digit number in ruby?如何在 ruby​​ 中生成一个随机的 10 位数字?
【发布时间】:2010-09-07 06:24:49
【问题描述】:

另外,如何将其格式化为用零填充的字符串?

【问题讨论】:

    标签: ruby random


    【解决方案1】:

    使用表达式“10 的 10 次方”的结果生成数字 call rand

    rand(10 ** 10)
    

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

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

    或者字符串的rjust方法

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

    【讨论】:

    • 我刚刚意识到,使用这种方法你仍然可以得到0000000000。有什么办法可以防止吗?
    • 不正确,因为有时它会返回少 1 或 2 位数的计数。即上面的 252402199、12348208。请检查我的答案。
    【解决方案2】:

    我想贡献一个我知道的最简单的解决方案,这是一个非常好的技巧。

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

    【讨论】:

    • 唯一的问题是它给了你一个字符串,所以如果你真的需要一个数字,你必须(再次)转换它——这有点乱。
    • 值得注意的是,它最多只能提供 16 位数字。
    • 不建议这样做。它并不总是预期的长度,因为rand 可能会返回一个低至0.0 的浮点值,结果字符串将是"0"。如果您想确认,请在irb 中通过运行(0.0).to_s[2..11] 尝试此操作。
    【解决方案3】:

    这是一种快速生成 10 位数字字符串的方法:

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

    【讨论】:

    • 第一个数字可能是零,但会产生九位数字。
    • @GeorgeYacoub 我认为 OP 想要一个零填充字符串作为最终结果。
    • 这确实满足了 OP 指出的所有要求——即使第一个数字是数字。
    • 实现相同目标的更高效方式:Array.new(10) { rand(10) }
    【解决方案4】:

    最直接的答案可能是

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

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

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

    【讨论】:

    • 这甚至比@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}}
    • 我刚试过这个,但从 0 开始永远无法观察到它,即使它有固定的长度。 10000.times.map{rand(1e9...1e10).to_i.to_s}.select!{|x| x.start_with?("0")} 产生 []
    • @OskarHolmkratz 此代码生成一个介于 1000000000 和 9999999999 之间的数字。
    • 这绝对是最好的答案。 ??我什至不知道 点变体。我一直用两个点。太好了。
    • 成功生成了 200 万个唯一号码。我使用了securerandom,因为 rand() 在 500k 时不再是唯一的。 SecureRandom.random_number(1e9...1e10).to_s[0..15].tr('.', '').to_i
    【解决方案5】:

    不要使用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 范围内的东西。

    我很高兴我有很好的测试,我希望你不会破坏你的系统。

    【讨论】:

      【解决方案6】:

      随机数生成

      使用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 password generator库,支持不同模式生成随机密码:

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

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

      【讨论】:

        【解决方案7】:

        仅仅因为没有提及,Kernel#sprintf 方法(或Powerpack Library 中的别名Kernel#format)通常优于String#% 方法,如Ruby Community Style Guide 中所述。

        当然,这值得商榷,但为了提供见解:

        @quackingduck 答案的语法是

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

        这种偏好的性质主要是由于% 的神秘性质。它本身不是很语义化,如果没有任何额外的上下文,它可能会与 % 模运算符混淆。

        来自Style Guide的示例:

        # 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') 一样。

        这只是说明了社区中的一种趋势,什么是“最好的”取决于你。

        this blogpost 中的更多信息。

        【讨论】:

          【解决方案8】:

          我最终使用了 Ruby 内核 srand

          srand.to_s.last(10)

          这里的文档:Kernel#srand

          【讨论】:

            【解决方案9】:

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

            '%011d' % rand(1e10)
            

            需要注意的是,1e10Float,而Kernel#rand 最终会在其上调用to_i,因此对于某些更高的值,您可能会遇到一些不一致的情况。为了更准确地使用文字,您还可以这样做:

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

            【讨论】:

              【解决方案10】:

              我只想修改第一个答案。 rand (10**10) 可能会生成 9 位随机数,如果 0 在第一位。为了确保 10 个精确的数字,只需修改

              code = rand(10**10)
              while code.to_s.length != 10
              code = rand(11**11)
              

              结束

              【讨论】:

                【解决方案11】:

                尝试使用 SecureRandom ruby​​ 库。

                它生成随机数,但长度不具体。

                通过此链接了解更多信息:http://ruby-doc.org/stdlib-2.1.2/libdoc/securerandom/rdoc/SecureRandom.html

                【讨论】:

                • 例如10.times.map{ SecureRandom.random_number(9)}.join
                • 我最终使用了以下方法,因为它比 10.times.map... SecureRandom.random_number(10**10).to_s 快​​了大约 25%
                【解决方案12】:

                生成n位随机数的最简单方法-

                Random.new.rand((10**(n - 1))..(10**n))
                

                生成 10 位数字号码 -

                Random.new.rand((10**(10 - 1))..(10**10))
                

                【讨论】:

                • 对于 10 位数字,范围应为 (10**(10 - 1))...(10**10),因为范围结束是一个 11 位数字,并且包含在使用 .. 作为范围运算符时的范围内。
                【解决方案13】:

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

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

                【讨论】:

                • 这确实是一个很好的解决方案,为什么这不是更多的投票?
                【解决方案14】:

                这种技术适用于任何“字母”

                (1..10).map{"0123456789".chars.to_a.sample}.join
                => "6383411680"
                

                【讨论】:

                  【解决方案15】:

                  在下面直接使用即可。

                  rand(10 ** 9...10 ** 10)
                  

                  只需在 IRB 上测试它。

                  (1..1000).each { puts rand(10 ** 9...10 ** 10) }
                  

                  【讨论】:

                  • 这将包括范围对象的最后一个数字吗?这实际上是 11 位数。
                  【解决方案16】:
                  rand(9999999999).to_s.center(10, rand(9).to_s).to_i
                  

                  rand.to_s[2..11].to_i
                  

                  你可以使用:

                  puts Benchmark.measure{(1..1000000).map{rand(9999999999).to_s.center(10, rand(9).to_s).to_i}}
                  

                  puts Benchmark.measure{(1..1000000).map{rand.to_s[2..11].to_i}}
                  

                  在 Rails 控制台中确认。

                  【讨论】:

                    【解决方案17】:

                    另一个答案,使用regexp-examples ruby​​ gem:

                    require 'regexp-examples'
                    
                    /\d{10}/.random_example # => "0826423747"
                    

                    这种方法不需要“用零填充”,因为您会立即生成String

                    【讨论】:

                      【解决方案18】:

                      要生成一个随机的 10 位字符串:

                      # This generates a 10-digit string, where the
                      # minimum possible value is "0000000000", and the
                      # maximum possible value is "9999999999"
                      SecureRandom.random_number(10**10).to_s.rjust(10, '0')
                      

                      下面是正在发生的事情的更多细节,通过将单行分成多行并带有解释变量来显示:

                        # Calculate the upper bound for the random number generator
                        # upper_bound = 10,000,000,000
                        upper_bound = 10**10
                      
                        # n will be an integer with a minimum possible value of 0,
                        # and a maximum possible value of 9,999,999,999
                        n = SecureRandom.random_number(upper_bound)
                      
                        # Convert the integer n to a string
                        # unpadded_str will be "0" if n == 0
                        # unpadded_str will be "9999999999" if n == 9_999_999_999
                        unpadded_str = n.to_s
                      
                        # Pad the string with leading zeroes if it is less than
                        # 10 digits long.
                        # "0" would be padded to "0000000000"
                        # "123" would be padded to "0000000123"
                        # "9999999999" would not be padded, and remains unchanged as "9999999999"
                        padded_str = unpadded_str.rjust(10, '0')
                      

                      【讨论】:

                        【解决方案19】:

                        这甚至适用于 ruby​​ 1.8.7:

                        rand(9999999999).to_s.center(10, rand(9).to_s).to_i

                        【讨论】:

                          【解决方案20】:

                          更好的方法是使用Array.new() 而不是.times.map。 Rubocop 推荐它。

                          例子:

                          string_size = 9
                          Array.new(string_size) do
                             rand(10).to_s
                          end
                          

                          Rubucop,TimesMap:

                          https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Performance/TimesMap

                          【讨论】:

                          • 它对我有用! (Array.new(string_size) { rand(10).to_s }).join
                          【解决方案21】:

                          在我的案例中,编号在我的模型中必须是唯一的,所以我添加了检查块。

                            module StringUtil
                              refine String.singleton_class do
                                def generate_random_digits(size:)
                                  proc = lambda{ rand.to_s[2...(2 + size)] }
                                  if block_given?
                                    loop do
                                      generated = proc.call
                                      break generated if yield(generated) # check generated num meets condition
                                    end
                                  else
                                    proc.call
                                  end
                                end
                              end
                            end
                            using StringUtil
                            String.generate_random_digits(3) => "763"
                            String.generate_random_digits(3) do |num|
                              User.find_by(code: num).nil?
                            end => "689"(This is unique in Users code)
                          

                          【讨论】:

                            【解决方案22】:

                            我做了这样的事情

                            x = 10  #Number of digit
                            (rand(10 ** x) + 10**x).to_s[0..x-1]
                            

                            【讨论】:

                              【解决方案23】:

                              随机 10 个数字:

                              require 'string_pattern'
                              puts "10:N".gen
                              

                              【讨论】:

                                猜你喜欢
                                • 2011-10-26
                                • 2018-05-20
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2012-04-20
                                • 2012-09-21
                                • 2016-03-27
                                • 2013-08-02
                                相关资源
                                最近更新 更多