Как определить длину Fixnum в Ruby?
В сценарии, который я пишу, я хочу найти длину Fixnum в Ruby. я мог бы сделать <num>.to_s.length
, но есть ли способ напрямую найти длину Fixnum без преобразования его в строку?
8 ответов
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) используйте абсолютное значение. Integer # абс
-123456.abs.digits
# => [6, 5, 4, 3, 2, 1]
Sidenote для 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)
Хотя цикл с верхним голосованием хорош, он не очень 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
Если вы не хотите использовать регулярные выражения, вы можете использовать этот метод:
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
Вам не нужно фантазировать, вы можете сделать это так просто.
def l(input)
output = 1
while input - (10**output) > 0
output += 1
end
return output
end
puts l(456)
Это может быть решением, чтобы узнать длину/количество/размер фиксированного номера.
irb(main):004:0> x = 2021
=> 2021
irb(main):005:0> puts x.to_s.length
4
=> nil
irb(main):006:0>