23

Possible Duplicate:
Turning long fixed number to array Ruby

Well, I have to iterate over the digits of a integer in Ruby. Right now I was just splitting it up into an array, and then iterating over that. However I was wondering if there was a faster way to do this?

Community
  • 1
  • 1
Rivasa
  • 6,510
  • 3
  • 35
  • 64

6 Answers6

47

The shortest solution probably is:

1234.to_s.chars.map(&:to_i)
#=> [1, 2, 3, 4]

A more orthodox mathematical approach:

class Integer
  def digits(base: 10)
    quotient, remainder = divmod(base)
    quotient == 0 ? [remainder] : [*quotient.digits(base: base), remainder]
  end
end

0.digits #=> [0]
1234.digits #=> [1, 2, 3, 4]
0x3f.digits(base: 16) #=> [3, 15]
tokland
  • 66,169
  • 13
  • 144
  • 170
  • To just iterate through the digits, you can also use array slice methods, right? n = 12.to_s sum = (n[0..1].to_i + n[1..2].to_i) product = (n[0,1].to_i * n[1,1].to_i) – Linju Jun 08 '17 at 16:09
15

You can use the old trick of modulus/divide by 10, but this won't be measurably faster unless you have huge numbers, and it will give the digits to you backwards:

i = 12345

while i > 0 
  digit = i % 10
  i /= 10
  puts digit
end

Output:

5
4
3
2
1
user229044
  • 232,980
  • 40
  • 330
  • 338
5
split=->(x, y=[]) {x < 10 ? y.unshift(x) : split.(x/10, y.unshift(x%10))}

split.(1000) #=> [1,0,0,0]
split.(1234) #=> [1,2,3,4]
Roberto Decurnex
  • 2,514
  • 1
  • 19
  • 28
5

Ruby has divmod, which will calculate both x%10and x/10 in one go:

class Integer
  def split_digits
    return [0] if zero?
    res = []
    quotient = self.abs #take care of negative integers
    until quotient.zero? do
      quotient, modulus = quotient.divmod(10) #one go!
      res.unshift(modulus) #put the new value on the first place, shifting all other values
    end
    res # done
  end
end

p 135.split_digits #=>[1, 3, 5]

For things like Project Euler, where speed is of some importance, this is nice to have. Defining it on Integer causes it to be available on Bignum too.

steenslag
  • 79,051
  • 16
  • 138
  • 171
5

I like to use enumerators for this purpose:

class Integer
  def digits
    to_s.each_char.lazy.map(&:to_i)
  end
end

This gives you access to all the good Enumerator stuff:

num = 1234567890

# use each to iterate over the digits
num.digits.each do |digit|
  p digit
end

# make them into an array
p num.digits.to_a     # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

# or take only some digits
p num.digits.take(5)  # => [1, 2, 3, 4, 5]

# ...
Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
2

Try mod by 10 (will give you the last digit), then divide by 10 (will give you the rest of digits), repeat this until you're down to the final digit. Of course, you'll have to reverse the order if you want to go through the digits from left to right.

Mohamed Nuur
  • 5,536
  • 6
  • 39
  • 55