Роман в целое число рефакторинг - PullRequest
0 голосов
/ 28 октября 2018

Я пишу метод roman_to_integer(roman_string), который переводит римскую цифру в целое число: от «IV» до 4, «XVI» до 16 и т. Д.

 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

Как мне сделать мойметод короче?Rubocop позволяет только 10 строк.Я пытаюсь, но всегда заканчивался хотя бы с 13.

Ответы [ 3 ]

0 голосов
/ 28 октября 2018

Если основной целью является уменьшение количества строк кода, можно сделать следующее.

Код

H = {"VI"=>" 4", "XI"=>" 9", "LX"=>" 40", "CX"=>" 90", "DC"=>" 400", "MC"=>" 900",
     "I"=>" 1", "V"=>" 5", "X"=>" 10", "L"=>" 50", "C"=>" 100", "D"=>" 500", "M"=>" 1000"}

def roman_to_integer(roman_string)
   roman_string.reverse.gsub(Regexp.union(H.keys), H).split.sum(&:to_i)
end

Примеры

%w| III LXIV CCXXVI CM CMXCVIII MDCCXII |.each {|s| puts "#{s}->#{ roman_to_integer(s)}"}
  # III->3
  # LXIV->64
  # CCXXVI->226
  # CM->900
  # CMXCVIII->998
  # MDCCXII->1712

Пояснение

Регулярные выражения анализируются слева направо, поэтому для использования одного из них нам нужно обратить roman_string в качестве первого шага,Это означает, что мы также должны поменять местами ключи в хэше.

Это использует форму String # gsub , которая использует хэш в качестве аргумента.Обратите внимание, что ключи H расположены в порядке убывания размера.Вот пример того, почему я это сделал.Предположим, указатель gsub находится на "V", а следующий символ - "I".Порядок клавиш приведет к тому, что gsub (что является жадным алгоритмом) будет соответствовать "VI", а не "V".

Для

roman_string = "CCXXVI"

шаги будут следующими.

k = H.keys
  #=> ["VI", "XI", "LX", "CX", "DC", "MC", "I", "V", "X", "L", "C", "D", "M"]
r = Regexp.union(H.keys)
  #=> /VI|XI|LX|CX|DC|MC|I|V|X|L|C|D|M/
t = s.gsub(r, H)
  #=> " 1 5 10 10 100 100"
a = t.split
  #=> ["1", "5", "10", "10", "100", "100"]
a.sum(&:to_i)
  # => 226

Обратите внимание: если нам дано

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 }

, мы можем вычислить H следующим образом.

H = ROMAN_TO_INT.map { |k,v| [k.reverse, " #{v}"] }.sort_by { |k,_| -k.size }.to_h
0 голосов
/ 30 октября 2018

Еще меньшая версия, использующая тот же трюк, что и 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
0 голосов
/ 28 октября 2018

На самом деле не рефакторинг, но возможность уменьшить количество строк:

ROMAN_TO_INT =
  {
    i: 1,
    v: 5,
    x: 10,
    l: 50,
    c: 100,
    d: 500,
    m: 1000
  }


def roman_to_int roman
  value_map = roman.split('').map { |e| ROMAN_TO_INT[e.downcase.to_sym] }
  value_map.map.with_index do |e, idx| 
    unless value_map[idx + 1].nil?
    then
      value_map[idx + 1] > e ? -e : e
    else e
    end
  end.sum
end

roman = "MDCCLXXVI"
roman_to_int roman #=> 1776

Не предупреждает в случае неверной римской записи, например:

roman = "VMII" # incorrect notation for 997
roman_to_int roman #=> 997

roman = "CMXCVII" # correct notation for 997
roman_to_int roman #=> 997
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...