Преобразование длинного фиксированного числа в массив Ruby

Есть ли в ruby ​​способ превратить fixnum, например 74239, в массив, например [7,4,2,3,9]?


person Ilya Nikiforov    schedule 16.10.2012    source источник
comment
Ответ mbds с использованием метода digits, представленного в Ruby 2.4, делает все остальные устаревшими.   -  person steenslag    schedule 19.11.2020


Ответы (7)


Вам не нужно совершать кругосветное путешествие по стране струн для такого рода вещей:

def digits(n)
  Math.log10(n).floor.downto(0).map { |i| (n / 10**i) % 10 }
end

ary = digits(74239)
# [7, 4, 2, 3, 9]

Это, конечно, предполагает, что n положителен, добавление n = n.abs в микс может позаботиться об этом, если это необходимо. Если вам нужно покрыть неположительные значения, то:

def digits(n)
  return [0] if(n == 0)
  if(n < 0)
    neg = true
    n   = n.abs
  end
  a = Math.log10(n).floor.downto(0).map { |i| (n / 10**i) % 10 }
  a[0] *= -1 if(neg)
  a
end
person mu is too short    schedule 16.10.2012
comment
@RyanBigg: Только если ты забыл школьную математику. - person mu is too short; 16.10.2012

Возможно, не самое элегантное решение:

74239.to_s.split('').map(&:to_i)

Выход:

[7, 4, 2, 3, 9]
person nneonneo    schedule 16.10.2012
comment
.map(&:to_i) чтобы сделать его более элегантным? - person oldergod; 16.10.2012
comment
Что происходит с -23.to_s.split('').map(&:to_i)? - person mu is too short; 16.10.2012
comment
Я немного придираюсь, но 74239.to_s.chars кажется более подходящим, чем 74239.to_s.split(''), особенно в сочетании с .map(&:to_i) :) - person Adam Eberlin; 29.10.2012
comment
Я думаю, что each_char было бы даже более подходящим, так как это позволило бы избежать промежуточного звена Array, созданного chars. - person Drenmi; 26.04.2015
comment
@Drenmi, я полагаю, что .chars сейчас в Enumerator, а не в Array. - person Nakilon; 19.06.2017

Метод divmod можно использовать для извлечения цифр по одной за раз.

def digits n
  n= n.abs
  [].tap do |result|
    while n > 0 
      n,digit = n.divmod 10
      result.unshift digit
    end
  end
end

Быстрый тест показал, что это быстрее, чем использование журнала для предварительного определения количества цифр, что само по себе быстрее, чем строковые методы.

bmbm(5) do |x|
  x.report('string') {10000.times {digits_s(rand(1000000000))}}
  x.report('divmod') {10000.times {digits_divmod(rand(1000000000))}}
  x.report('log') {10000.times {digits(rand(1000000000))}}
end

#=>
             user     system      total        real
string   0.120000   0.000000   0.120000 (  0.126119)
divmod   0.030000   0.000000   0.030000 (  0.023148)
log      0.040000   0.000000   0.040000 (  0.045285)
person Frederick Cheung    schedule 16.10.2012

Вы можете преобразовать в строку и использовать метод chars:

74239.to_s.chars.map(&:to_i)

Выход:

[7, 4, 2, 3, 9]

Это немного более элегантно, чем расщепление.

person Paulo Fidalgo    schedule 29.10.2015

Начиная с Ruby 2.4, целые числа (FixNum исчезли в 2.4 +) имеют встроенный метод digits, который извлекает их в массив их цифр:

74239.digits
=> [9, 3, 2, 4, 7]

Если вы хотите сохранить порядок цифр, просто соедините цепочку reverse:

74239.digits.reverse
=> [7, 4, 2, 3, 9]

Документы: https://ruby-doc.org/core-2.4.0/Integer.html#method-i-digits

person mbds    schedule 11.05.2020

Вы также можете использовать Array.new вместо map:

n = 74239

s = Math.log10(n).to_i + 1 # Gets the size of n

Array.new(s) { d = n % 10; n = n / 10; d }.reverse 
person izaban    schedule 27.09.2016

В Ruby 2.4 целые числа будут иметь метод digits.

person steenslag    schedule 02.11.2016