如何确定Ruby中Fixnum的长度?

在我写的脚本中,我想在Ruby中找到Fixnum的长度。 我可以做.to_s.length ,但有没有办法直接找到Fixnum的长度而不将其转换为String?

 puts Math.log10(1234).to_i + 1 # => 4 

您可以将它添加到Fixnum,如下所示:

 class Fixnum def num_digits Math.log10(self).to_i + 1 end end puts 1234.num_digits # => 4 

Ruby 2.4有一个Integer#digits方法,它返回一个包含数字的数组。

 num = 123456 num.digits # => [6, 5, 4, 3, 2, 1] num.digits.count # => 6 

编辑:

要处理负数(感谢@MatzFan),请使用绝对值。 整数#ABS

 -123456.abs.digits # => [6, 5, 4, 3, 2, 1] 

尽管排名靠前的循环很好,但它不是很好的Ruby,并且对于大数字来说会很慢,.to_s是一个内置函数,因此速度会快得多。 几乎所有内置函数都比构造循环或迭代器快得多。

其他方式:

 def ndigits(n) n=n.abs (1..1.0/0).each { |i| return i if (n /= 10).zero? } end ndigits(1234) # => 4 ndigits(0) # => 1 ndigits(-123) # => 3 

Ruby 2.4+的旁注

我在不同的解决方案上运行了一些基准测试,而Math.log10(x).to_i + 1实际上比x.to_s.length 。 来自@Wayne Conrad的评论已经过时了。 使用digits.count的新解决方案远远落后,特别是对于更大的数字:

 with_10_digits = 2_040_240_420 print Benchmark.measure { 1_000_000.times { Math.log10(with_10_digits).to_i + 1 } } # => 0.100000 0.000000 0.100000 ( 0.109846) print Benchmark.measure { 1_000_000.times { with_10_digits.to_s.length } } # => 0.360000 0.000000 0.360000 ( 0.362604) print Benchmark.measure { 1_000_000.times { with_10_digits.digits.count } } # => 0.690000 0.020000 0.710000 ( 0.717554) with_42_digits = 750_325_442_042_020_572_057_420_745_037_450_237_570_322 print Benchmark.measure { 1_000_000.times { Math.log10(with_42_digits).to_i + 1 } } # => 0.140000 0.000000 0.140000 ( 0.142757) print Benchmark.measure { 1_000_000.times { with_42_digits.to_s.length } } # => 1.180000 0.000000 1.180000 ( 1.186603) print Benchmark.measure { 1_000_000.times { with_42_digits.digits.count } } # => 8.480000 0.040000 8.520000 ( 8.577174) 

如果您不想使用正则表达式,可以使用此方法:

 def self.is_number(string_to_test) is_number = false # use to_f to handle float value and to_i for int string_to_compare = string_to_test.to_i.to_s string_to_compare_handle_end = string_to_test.to_i # string has to be the same if(string_to_compare == string_to_test) is_number = true end # length for fixnum in ruby size = Math.log10(string_to_compare_handle_end).to_i + 1 # size has to be the same if(size != string_to_test.length) is_number = false end is_number end