我正在运行TestFirstRuby,并且我被问题12卡住了,构建一个反向波兰语记数计算器。我已经通过了所有的测试,除了最后一个测试,要求我接受一个字符串("1 2 3* +“,然后是"1 2 3*+4 5/ -"),然后计算表达式。
我要做的是将字符串转换为数组,将数字转换为整数,将运算符转换为符号,然后遍历数组,并在任何时候计算运算符的表达式。
以下是代码的相关部分:
def initialize
@expression = ''
end
def tokens(string)
tokens = string.split(' ')
tokens.map! { |digit| /[0-9]/.match(digit) ? digit.to_i : digit.to_sym }
end
def evaluate(string)
#1 2 3 * +
#1 2 3 * + 4 5 - /
total = 0
@expression = tokens(string)
@expression.map!{|item|
index = @expression.index(item)
if item == :+
total = total + (@expression[index-1] + @expression[index-2])
2.times {@expression.delete_at(index-1)}
elsif item == :-
total = total + (@expression[index-1] - @expression[index-2])
2.times {@expression.delete_at(index-1)}
elsif item == :x
total = total + (@expression[index-1] * @expression[index-2])
2.times {@expression.delete_at(index-1)}
elsif item == :/
total = total + (@expression[index-1].to_f / @expression[index-2])
2.times {@expression.delete_at(index-1)}
end
}
total
end我想要发生的是这样的:对于数组中的每一项,它检查它是否与任何符号匹配。如果有匹配,它会将元素从符号后面两个空格改为表达式的任何值(因此2 3*变成5 3 *)。然后,我尝试删除操作符和它之前的整数,只留下求值的值。我通过在操作符之前的索引上运行delete_at两次来做到这一点(理想情况下,5 3*转到5*,然后只运行5)。然后它将移动到数组中的下一个元素。
我认为是错误的,并且我在修复时遇到了麻烦:我认为这里的变量作用域发生了一些问题。我试图让表达式在每次对each循环中当前所在的元素运行代码时永久更改。对于每个元素,使用@expression.index(item)设置一个变量'index‘。这应该为each循环中的每个元素重置。我认为发生的事情是,对于each循环的每次迭代,都会调用原始的@expression数组,而each循环的每次迭代都没有改变。
我得到的错误是,当它到达第一个测试字符串('1 2 3* +')末尾的'+‘时,它试图使用:x添加,这意味着当它调用两个变量相加时( @expression -1+@expression it 2),它会拉出符号,我认为这个符号应该已经从@expression中删除了。所以我希望6+1的计算结果是3+ :x,这是行不通的。它从原始数组中拉出元素,而不是在数组发生变化时从数组中拉出。
希望我已经解释得足够清楚了。任何建议都是很棒的。我在想,有一些事情正在发生,但我找不到任何针对这种问题的具体东西来帮助我。我尝试过不同的编码方式(.map、.each_with_index、.map.with_index等),每次都遇到同样的问题。
发布于 2014-08-17 11:35:35
你有大量的冗余代码。特别是,您将复制四个运算符中的每个运算符的操作。这是一种更像Ruby的实现计算器的方式。
代码
def evaluate(string)
arr = create_arr(string)
until arr.size == 1
i = arr.index(arr.find { |e| e.is_a? Symbol })
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
arr.delete_at(i)
arr.delete_at(i-1)
end
arr.first
end
def create_arr(string)
string.split(/\s+/).map { |e| e =~ /-?[0-9]+/ ? e.to_i : e.to_sym }
endcreate_arr中的行也可以以: e }结尾(sent接受方法的字符串或符号),在这种情况下,e.is_a? Symbol将更改为e.is_a? String。
示例
evaluate("3 4 * 2 / 3 - 2 *") #=> 6
evaluate("10 2 / 3 + 2 / 2 -") #=> 2
evaluate("8 -2 / 1 +") #=> -3
evaluate("5 1 2 + 4 * + 3 -") #=> 14说明
假设
string = "2 3 4 * 2 / +"第一步
arr = create_arr(string) #=> [2, 3, 4, :*, 2, :/, :+]
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :*
i = arr.index(v) #=> 3
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[1] = arr[1].send(arr[3], arr[2])
# arr[1] = 3.send(:*, 4) #=> 12
arr #=> [2, 12, 4, :*, 2, :/, :+]
arr.delete_at(i) #=> :*
arr #=> [2, 12, 4, 2, :/, :+]
arr.delete_at(i-1) #=> 4
arr #=> [2, 12, 2, :/, :+]第二步
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :/
i = arr.index(v) #=> 3
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[1] = arr[1].send(arr[3], arr[2])
# arr[1] = 12.send(:/, 2) #=> 6
arr #=> [2, 6, 2, :/, :+]
arr.delete_at(i) #=> :/
arr #=> [2, 6, 2, :+]
arr.delete_at(i-1) #=> 2
arr #=> [2, 6, :+]第三步
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :+
i = arr.index(v) #=> 2
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[0] = arr[0].send(arr[2], arr[1])
# arr[0] = 2.send(:+, 6) #=> 8
arr #=> [8, 6, :+]
arr.delete_at(i) #=> :+
arr #=> [8, 6]
arr.delete_at(i-1) #=> 6
arr #=> [8]第四步
arr.size == 1 #=> true
arr.first #=> 8https://stackoverflow.com/questions/25345541
复制相似问题