Search code examples
rubyrefactoring

Roman to integer refactored


I'm writing a method roman_to_integer(roman_string), which translates a roman numeral into its integer: 'IV' to 4, 'XVI' to 16, etc.

 ROMAN_TO_INT = {
      "I" => 1,
      "IV" => 4,
      "V" => 5,
      "IX" => 9,
      "X" => 10,
      "XL" => 40,
      "L" => 50,
      "XC" => 90,
      "C" => 100,
      "CD" => 400,
      "D" => 500,
      "CM" => 900,
      "M" => 1000
    }

    def roman_to_integer(roman_string)
      # TODO: translate roman string to integer
      number = 0
      str = roman_string.dup
      until str.size.zero?
        last_two_characters = str.slice(-2, 2)
        if ROMAN_TO_INT.key?(last_two_characters)
          number += ROMAN_TO_INT[last_two_characters]
          str.chop!
        else
          number += ROMAN_TO_INT[str.slice(-1)]
        end
        str.chop!
      end
      number
    end

How can I make my method shorter? Rubocop only allows 10 lines. I'm trying, but always ended with at least 13.


Solution

  • An even smaller version, using the same trick as iGian:

    ROMAN_TO_INT =
    {
      i: 1,
      v: 5,
      x: 10,
      l: 50,
      c: 100,
      d: 500,
      m: 1000
    }
    
    def roman_to_int(roman)
      numbers = roman.downcase.chars.map { |char| ROMAN_TO_INT[char.to_sym] }.reverse
      numbers.inject([0, 1]) do |result_number, int|
        result, number = result_number
        int >= number ? [result + int, int] : [result - int, number]
      end.first
    end