Turning long fixed number to array Ruby
Asked Answered
B

7

11

Is there a method in ruby to turn fixnum like 74239 into an array like [7,4,2,3,9]?

Beauty answered 16/10, 2012 at 5:22 Comment(1)
The answer of mbds, using the digits method introduced in Ruby 2.4 makes all others obsolete.Telemechanics
H
9

You don't need to take a round trip through string-land for this sort of thing:

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

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

This does assume that n is positive of course, slipping an n = n.abs into the mix can take care of that if needed. If you need to cover non-positive values, then:

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
Halinahalite answered 16/10, 2012 at 5:36 Comment(1)
@RyanBigg: Only if you've forgotten your high school math.Halinahalite
C
18

Maybe not the most elegant solution:

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

Output:

[7, 4, 2, 3, 9]
Cursorial answered 16/10, 2012 at 5:25 Comment(5)
.map(&:to_i) to get it a bit more elegant?Juniejunieta
What happens to -23.to_s.split('').map(&:to_i)?Halinahalite
I'm nitpicking a bit here, but 74239.to_s.chars seems more appropriate than 74239.to_s.split(''), especially when used in conjunction with .map(&:to_i) :)Stertor
I think each_char would be even more appropriate, as it would avoid the intermediate Array created by chars.Linea
@Drenmi, I suppose .chars in Enumerator currently, not Array.Townie
H
9

You don't need to take a round trip through string-land for this sort of thing:

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

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

This does assume that n is positive of course, slipping an n = n.abs into the mix can take care of that if needed. If you need to cover non-positive values, then:

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
Halinahalite answered 16/10, 2012 at 5:36 Comment(1)
@RyanBigg: Only if you've forgotten your high school math.Halinahalite
S
8

As of Ruby 2.4, integers (FixNum is gone in 2.4+) have a built-in digits method that extracts them into an array of their digits:

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

If you want to maintain the order of the digits, just chain reverse:

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

Docs: https://ruby-doc.org/core-2.4.0/Integer.html#method-i-digits

Shellbark answered 11/5, 2020 at 8:20 Comment(0)
B
5

The divmod method can be used to extract the digits one at a time

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

A quick benchmark showed this to be faster than using log to find the number of digits ahead of time, which was itself faster than string based methods.

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)
Betseybetsy answered 16/10, 2012 at 7:54 Comment(0)
N
5

You can convert to string and use the chars method:

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

Output:

[7, 4, 2, 3, 9]

Its a bit more elegant than splitting.

Nollie answered 29/10, 2015 at 1:14 Comment(0)
H
1

You can also use Array.new instead of 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 
Hodgkinson answered 27/9, 2016 at 18:10 Comment(0)
T
1

In Ruby 2.4, integers will have a digits method.

Telemechanics answered 2/11, 2016 at 12:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.