我正在写一个方法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结尾。
答案 0 :(得分:1)
并不是真正的重构,而是一种减少行数的选项:
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
答案 1 :(得分:1)
如果主要目标是减少代码行数,则可以执行以下操作。
代码
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
答案 2 :(得分:1)
一个更小的版本,使用了与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