2014-09-29 4 views
3

В попытке кодирования, которую я недавно попытался, я нашел это в качестве альтернативного решения для преобразования чисел в римские цифры. Я действительно не понимаю, как работает этот код. Я только что понял, что делает divmod, но еще, я очень смущен.Римские цифры в Ruby

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

    roman_arr.reduce("") do |res, (arab, roman)| 
     whole_part, num = num.divmod(arab) 
     res << roman * whole_part 
    end 
    end 
end 
+3

Попробуйте положить некоторую отладочную печать в цикле. Кроме того, вы реализовали свое собственное решение, прежде чем найти его? Если вы думали долго и трудно, и это сделали - это один будет иметь смысл. –

+0

BTW, попробуйте прочитать это сообщение: http://tech.tulentsev.com/2014/02/kata-convert-numbers-to-roman-numerals/. Часть цикла отличается, но есть больше объяснений. :) –

ответ

6

сокращение/сложение - функциональное программирование, эквивалентное циклам, найденным на императивных языках. Рубин способен на оба.

foo.reduce("") { |a, i| a + i } эквивалентно

a = "" 
foo.each {|i| a = a + i} 
a 

num = self линия сохраняет экземпляр (число, которое принимает метод to_roman) в локальной переменной, так что вы можете использовать его в блоке, который вы передаете, чтобы уменьшить.

3

Я добавил некоторое объяснение в код, надеюсь, что это ясно сейчас. Вы никогда не напишете это так, хотя код, который вы опубликовали, в порядке.

class Integer 

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

    remaining = self # the integer on which this method is called 
    empty_string = "" # startvalue of result 

    return_value = roman_arr.inject(empty_string) do |result, (arab, roman)| 
     # inject = reduce, for each element of our hash 
     # arab and roman are the key and value part of the hash elements, result is result from previous iteration 
     p [result, arab, roman,remaining.divmod(arab)] # lets's see what happens 
     # number of times the remaining can be divided with the value of this roman, the remaining becomes the rest 
     whole_part, remaining = remaining.divmod(arab) 
     result << roman * whole_part # if whole_part == 0 nothing happens for this roman 
    end 

    return return_value 

    end 
end 

puts 555.to_roman_explained 

# gives 

# ["", 1000, "M", [0, 555]] 
# ["", 900, "CM", [0, 555]] 
# ["", 500, "D", [1, 55]] first time the integer is dividable by the value of the roman 
# ["D", 400, "CD", [0, 55]] our result now has the roman D 
# ["D", 100, "C", [0, 55]] 
# ["D", 90, "XC", [0, 55]] 
# ["D", 50, "L", [1, 5]] etc 
# ["DL", 40, "XL", [0, 5]] 
# ["DL", 10, "X", [0, 5]] 
# ["DL", 9, "IX", [0, 5]] 
# ["DL", 5, "V", [1, 0]] etc 
# ["DLV", 4, "IV", [0, 0]] 
# ["DLV", 1, "I", [0, 0]] 
# DLV 
1

Я нашел его легче, если реверсивный номер заранее, как:

def new_roman(arabic_number) 
    symbols = {0=>["I","V"],1=>["X","L"],2=>["C","D"],3=>["M"]} 
    reversed_digits = arabic_number.to_s.split(//).reverse 
    romans =[] 
    reversed_digits.length.times do |i| 
    if reversed_digits[i].to_i< 4 
     romans<<(symbols[i][0]*reversed_digits[i].to_i) 
    elsif reversed_digits[i].to_i == 4 
     romans<<(symbols[i][0]+ symbols[i][1]) 
    elsif reversed_digits[i].to_i == 9 
     romans<<(symbols[i][0] + symbols[i+1][0]) 
    else 
     romans<<(symbols[i][1] + (symbols[i][0]*((reversed_digits[i].to_i)-5))) 
    end 
    end 
    romans.reverse.join("") 
end 
Смежные вопросы