3
\$\begingroup\$

My goal here is pretty simple, I want to turn a number like 12435987234 into an array of integers in reverse order. So that would look like:

[4,3,2,7,8,9,5,3,4,2,1]

I want to do this without changing the number to a string and back. Really, I don't want to convert it at all but I'm open to hearing ideas around this.

I've found one way to do in ruby via #divmod but suspect there is a more perfomant way.

# turns 1234 into
# [4,3,2,1]
def reversed_digits(val)
  quot = val
  results = []
  while quot > 0 do
    quot, remainder = quot.divmod(10)
    results << remainder
  end
  results
end

puts reversed_digits(1234)
=> [4,3,2,1]
\$\endgroup\$
  • 1
    \$\begingroup\$ I benchmarked doing it with a string, and it's about 3x faster than this method. Are you trying to do it without conversion just for the intellectual challenge? \$\endgroup\$ – Jonah Jan 21 '16 at 1:15
  • \$\begingroup\$ Thanks @Jonah - I saw some similar benchmark results on my end and was hoping to tighten the above up and do a few other comparisons as well. So yes, intellectual challenge you could say. \$\endgroup\$ – Anthony Jan 21 '16 at 1:21
  • \$\begingroup\$ What is the reverse of 0? \$\endgroup\$ – greybeard Jan 21 '16 at 1:26
  • \$\begingroup\$ @greybeard fair question. This method today takes integers roughly the size of a credit card number (16-24) digits so the scenario smaller isn't a concern and I would likely guard against it. \$\endgroup\$ – Anthony Jan 21 '16 at 1:29
  • 1
    \$\begingroup\$ If you mention data like card numbers; be aware such data may have leading zeros, so they might be stored as strings rather than numbers, and conversion to string would not be necessary at all. However, if they are numeric variables, possibly your conversion routine should take additional parameter to describe the output size (number of items to pad to with zeros)? If implemented, that would cover the zero input value case, too, with desired_output_length=1. \$\endgroup\$ – CiaPan Jan 21 '16 at 10:41
1
\$\begingroup\$

I don't think your algorithm can be improved in speed. I'd propose a different implementation, though, a more shorter recursive function:

def reversed_digits(num, base: 10)
  quotient, remainder = num.divmod(base)
  [remainder] + (quotient == 0 ? [] : reversed_digits(quotient, base: base))
end
\$\endgroup\$
  • \$\begingroup\$ I don't think keyword parameters should be used here. Also your code is not tail-recursive unlike OP's one. \$\endgroup\$ – Nakilon Jan 21 '16 at 13:18
  • \$\begingroup\$ why is it not? reversed_digits is the final call in the function, when it recurses \$\endgroup\$ – Jonah Jan 21 '16 at 18:31
  • \$\begingroup\$ @Jonah: It's not tail-recursive, the recursive call is inside another expression. We would just need to add an accumulator. \$\endgroup\$ – tokland Jan 21 '16 at 18:39
  • \$\begingroup\$ ah, i see it now. \$\endgroup\$ – Jonah Jan 21 '16 at 18:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.