1
\$\begingroup\$

My exercise was to take a string of numbers, such as "1234" and return them as an integer 1234. However, I wasn't allowed to use #to_i, #to_f, Integer, etc.

def convert(int)
  x = 0
  array = int.split('')
  array.each.with_index do |y, i|
    x = (x + (y.hex))
    x = x * 10 unless i == array.length-1
  end
  return x
end

p convert('1234')
p convert('3225')
p convert('4321') == 4321
p convert('570') == 570

When I first started on this exercise, I wondered if I would be able to convert the String into a binary, octal, or other type of representation. Then, take that representation and convert it into integers.

Unfortunately, using #pack and #unpack resulted in more strings, and I couldn't really understand some of the methods that I could use with pack/unpack. Right now I don't have much knowledge in programming, so I couldn't really figure out how to take those strings and parse them into the Integers that I wanted. (My math kinda sucks too...)

Then I read about hex some more and realized that the hex representation of numbers 0-9 are the same as the integers! So I simply converted each number to a hex, added it to a variable and multiplied it by 10 with each iteration of the loop.

I know there's probably a better way to do this, but this is what I came up with.

I know another way (and possibly simpler) is to make a hash of 10 numbers, 0 - 9, with the keys being the Stringed numbers and their values being Integers, then iterating through that.

Anyways, please let me know what you think of my code and my thought process, and suggest what you can.

\$\endgroup\$
  • \$\begingroup\$ Are you allowed to use hex? \$\endgroup\$ – Stefan Sep 19 '17 at 7:50
3
\$\begingroup\$

So I think using hex isn't in the spirit of the challenge, but that part is easy anyway:

def to_i(digit)
  '0123456789'.index(digit)
end

Your hash idea would have worked fine here too, but the above is a bit terser.

The rest is a good fit for reduce:

def convert(str)
  str.split('').reduce(0) { |m,x| 10 * (m + to_i(x)) } / 10 
end

Or you can forget splitting the solution into 2 functions and just do a 1 liner:

def convert(str)
  str.split('').reduce(0) { |m,x| 10 * (m + '0123456789'.index(x)) } / 10 
end

Finally, another alternative which sacrifices some brevity to mirror the definition of what a number is even more closely:

def convert(str)
  str.split('').reverse().map.with_index { |x,i| to_i(x) * 10**i }.reduce(:+)
end
\$\endgroup\$
  • \$\begingroup\$ Thank you! I also found @MarcRohloff's answer to be helpful. Thank you for the comments and I will study these answers more. \$\endgroup\$ – Nathan Sep 14 '17 at 2:56
1
\$\begingroup\$

I think you make it complex by the way you do your multiplication. Instead of

x = 0
array.each.with_index do |y, i|
  x = (x + (y.hex))
  x = x * 10 unless i == array.length-1
end

I would do:

x = 0
array.each.with do |y|
  x = x * 10 + y.hex
end

I would also agree that using hex is not what was wanted if you were asked not to use to_i et al. I would use Jonah's suggestion or possibly y.ord-'0'.ord.

If I wanted to handle multiple bases I would write something like:

DIGITS = '01234567890abcdefghijklmnopqrstuvwxyz';
def convert(string, base=10)
  digits = string.split('')
  digits.reduce(0) do |accumulator, digit|
    value = DIGITS.index(digit)
    raise "Invalid digit #{digit}" unless value && value < base
    accumulator * base + value
  end
end
\$\endgroup\$

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.