2015-09-06 100 views
0

通過克里斯派恩的學習編程和編號爲羅馬數字轉換項目。下面的代碼可以工作,但是如果(和結束)語句都很糟糕。但是,當我使用elsif程序不響應(似乎凍結)。任何想法都會有幫助!如何減少if語句?

def calc input 

roman_numeral = '' 

while true 
if input >= 1000 
    roman_numeral += 'M' * (input/1000) 
    input = input - (1000 * (input/1000)) 

    if input <= 999 || input >= 500 
    roman_numeral += 'D' * (input/500) 
    input = input - (500 * (input/500)) 

    if input <= 499 || input >= 100 
    roman_numeral += 'C' * (input/100) 
    input = input - (100 * (input/100)) 

    if input <= 99 || input >= 50 
    roman_numeral += 'L' * (input/50) 
    input = input - (50 * (input/50)) 

    if input <= 49 || input >= 10 
    roman_numeral += 'X' * (input/10) 
    input = input - (10 * (input/10)) 

    if input <= 9 || input >= 5 
    roman_numeral += 'V' * (input/5) 
    input = input - (5 * (input/5)) 

    if input <= 4 || input >= 1 
    roman_numeral += 'I' * (input/1) 
    input = input - (1 * (input/1)) 

    puts roman_numeral 

    break 
end 
end 
end 
end 
end 
end 
end 
end 
end 


puts 'Give me a number, any number:' 
input = gets.chomp.to_i 
calc(input) 
+0

情況下輸入學習編程第二; 當1..4羅馬數字+ = '我' *(輸入/ 1); ... 當5..9羅馬數字+ = 'V' *(輸入/ 5); ... –

回答

3

這是方便的是使用該方法Enumerable#find以與陣列:

ARR = [[1000,'M'], [ 500,'D'], [100,'C'], [50,'L'], [10,'X'], [5,'V'], [1,'I']] 

def which(input) 
    ARR.find { |v,_| input >= v } 
end 

which(2) #=> [1, "I"] 
which(7) #=> [5, "V"] 
which(17) #=> [10, "X"] 
which(77) #=> [50, "L"] 
which(777) #=> [500, "D"] 
which(7777) #=> [1000, "M"] 

假設你的整數轉換爲羅馬數字,考慮利用該方法Fixnum#divmod的。假設整數爲2954和你已經確定有兩個"M"的和一個"D"(所以你的羅馬數字字符串的開頭是"MMD"),以及454被遺留下來的。然後:

c, rem = 454.divmod(100) 
    #=>[4, 54] 
c #=> 4 
rem #=> 54 

告訴你有四個"C"的與54遺留下來的。

"C"的寫"CD"(不"CCCC"),然而,您可能要使用的哈希如下列:

REP = {..., "C"=>["C", "CC", "CCC", "CD"], ...} 

"C"數轉換的一個羅馬數字。在這裏你可以附加REP["C"][4-1] #=> "CD""MMD""MMD" << "CD" #=> "MMDCD"

+0

卡里 - 感謝您的快速和詳細的反應。在較高的層面上它是有道理的,但是我認爲在我能夠正確實施你所建議的方法之前,我有一段路要走。雖然我已經得到了你:對初學者紅寶石主義者的資源有什麼建議?正如我在文章中提到的,我現在正在通過Pragmatic的Programming for Beginners,我很享受。任何其他建議將不勝感激。 – cmrnwllsbrn

+0

以下是一些可能性:[Ruby學習中的核心Ruby課程](http://rubylearning.org/classes/),[Code School](https://www.codeschool.com/courses/try-ruby)以及那些列於[iwantolearnruby](http://iwanttolearnruby.com/)。 –

1

從卡里Swoveland答案就是減少你的if塊嵌套一個很好的方式。

他的答案告訴你哪個數字隨之而來的,而不是有多少(在你的代碼)。綁在一起,它以自然的方式是一個遞歸函數調用:

class Romans 
    def self.calc(input, acc = "") 
    raise ArgumentError.new("Roman Numerals must be positve") if input < 0 
    raise ArgumentError.new("Roman Numerals must be integers") if ! input.is_a? Integer 

    return acc if input == 0 
    amount, numeral = which(input) 
    acc += numeral 
    input -= amount 
    calc(input, acc) 
    end 

    @@ARR = [[1000,'M'], [ 500,'D'], [100,'C'], [50,'L'], [10,'X'], [5,'V'], [1,'I']] 
    def self.which(input) 
    @@ARR.find { |v,_| input >= v } 
    end 
end 

在使用中:

pry(main)> (1..10).each{|i| puts "#{i}=> #{Romans.calc(i)}"} 
1=> I 
2=> II 
3=> III 
4=> IIII 
5=> V 
6=> VI 
7=> VII 
8=> VIII 
9=> VIIII 
10=> X 

pry(main)> [Random.rand(1..100000)].each{|i| puts "#{i}=> #{Romans.calc(i)}"} 
63124=> MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMCXXIIII 

注意Ruby沒有TCO,等會吹堆棧足夠大數字 - 但如果您需要800萬的羅馬數字版本,您可能需要編寫一些新的字母。

+0

克里斯 - 感謝您的回覆。正如瓦特卡里的迴應一樣,這很有道理,但是我認爲在我能夠利用你的方法之前,我還有一點距離。這裏總共noob。無論如何,謝謝! – cmrnwllsbrn

0

下面是使用字符串乘法的一個。例如:( 'M' ×3)= 'MMM'

def to_roman(number) 
    raise 'Must use positive numbers.' if number <= 0 
    roman = '' 

    roman << 'M' * (number  /1000) 
    roman << 'D' * (number % 1000/500) 
    roman << 'C' * (number % 500/100) 
    roman << 'L' * (number % 100/ 50) 
    roman << 'X' * (number % 50/ 10) 
    roman << 'V' * (number % 10/ 5) 
    roman << 'I' * (number % 5/ 1) 

    roman 
end 

puts to_roman(1234) # <-- test 

參考:由Chris鬆