如何减少if语句?

问题描述:

通过克里斯派恩的学习编程和编号为罗马数字转换项目。下面的代码可以工作,但是如果(和结束)语句都很糟糕。但是,当我使用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); ... –

这是方便的是使用该方法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/)。 –

从卡里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

下面是使用字符串乘法的一个。例如:( '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松