我尝试创建一个将字符串作为输入的方法,如果该字符串包含one
,two
,three
,four
,{ {1}},five
,six
,seven
或eight
将它们计为整数并添加它们,例如:
nine
我想通过单词拆分给定的字符串并将它们放入一个数组中,以便我可以迭代它并检查位置secret_code("one on one") #=> 2
secret_code("five monkeys in three farms") #=> 8
secret_code("") #=> 0
secret_code("fivethreeone") #=> 0
处的元素是否等于数字,并将其对应的值添加到变量中。到目前为止,这是我的代码:
i
我不太确定如何迭代数组。现在它为所有内容打印def secret_code(a)
arr = a.split(/\W+/)
i = 0
l = arr.size
num = 0
puts arr
if !arr.any?
0
end
while i < l do
case arr
when arr[i] == "one"
num += 1
exit
when arr[i] == "two"
num += 2
exit
when arr[i] == "three"
num += 3
exit
when arr[i] == "four"
num += 4
exit
when arr[i] == "five"
num += 5
exit
when arr[i] == "six"
num += 6
exit
when arr[i] == "seven"
num += 7
exit
when arr[i] == "eight"
num += 8
exit
when arr[i] == "nine"
num += 9
exit
end
i+=1
end
puts num
end
secret_code("one on one") #=> 2
secret_code("five monkeys in three farms") #=> 8
secret_code("") #=> 0
secret_code("fivethreeone") #=> 0
。
答案 0 :(得分:2)
问题在于:
case arr
when arr[i] == "one"
num += 1
# ...
end
在case
声明中,您在每个when
之后给出的值将与您在case
之后给出的值进行比较。换句话说,您的case
语句将首先(arr[i] == "one") === arr
,然后(arr[i] == "two") === arr
,依此类推。由于arr[i] == "one"
会返回true
或false
,而true === arr
和false === arr
永远不会成立,因此case
语句中的任何条件都不会满足。
最简单的解决方法是:
case arr[i]
when "one"
num += 1
when "two"
num += 2
when "three"
num += 3
# ...
end
此代码的作用是将arr[i]
与"one"
的值进行比较,然后比较"two"
,依此类推,从而产生预期的行为。
另请注意,我删除了exit
。在Ruby中,exit
退出程序。我猜你试图像你一样在其他编程语言中使用break
。你不需要这里,因为Ruby case
陈述没有&#34;直播&#34;像某些语言switch
一样。 <{1}}语句中只有一个when
匹配。
我的代码还有一些注意事项:
此代码无法执行任何操作:
case
你不能对if !arr.any?
0
end
做任何事情,所以它就会消失在虚空之中。您可能希望尽早从方法返回0
。一个更好的习语就是这样:
return 0
return 0 if arr.empty?
在Ruby中,使用while
来迭代数组的元素会更常见:
Enumerable#each
通过将arr.each do |word|
case word
when "one"
# ...
# ...
end
end
语句视为返回值的表达式,可以使case
语句更简洁:
num += case arr[i]
when "one" then 1
when "two" then 2
when "three" then 3
# ...
else 0
end
您可以使用哈希而不是case
语句使其更简洁:
word_values = {
"one" => 1, "two" => 2, "three" => 3,
"four" => 4, "five" => 5, "six" => 6,
"seven" => 7, "eight" => 8, "nine" => 9
}
word_values.default = 0
arr.each do |word|
num += word_values[word]
end
迭代单词数组并在word_values
哈希中查找每个单词。如果哈希中的单词不是,则会返回默认值0
。
使用word_values
哈希,您还可以执行以下操作:
values = arr.map {|word| word_values[word] }
puts values.reduce(:+)
这使用map
将单词数组转换为值数组,例如"five monkeys in three farms"
变为[5, 0, 0, 3, 0]
。然后,它使用reduce
(也称为inject
)来计算值的总和。
将所有这些改进放在一起,我们有:
WORD_VALUES = {
"one" => 1, "two" => 2, "three" => 3,
"four" => 4, "five" => 5, "six" => 6,
"seven" => 7, "eight" => 8, "nine" => 9
}
WORD_VALUES.default = 0
def secret_code(str)
str.split(/\W+/)
.map {|word| WORD_VALUES[word] }
.reduce(:+) || 0
end
puts secret_code("one on one") # => 2
puts secret_code("five monkeys in three farms") # => 8
puts secret_code("") # => 0
puts secret_code("fivethreeone") # => 0
(在Ruby 2.3中,你实际上可以做.map(&WORD_VALUES)
,这非常简洁。)
这是另一种方法,效率稍高:
def secret_code(str)
str.split(/\W+/).reduce(0) {|sum, word| sum + WORD_VALUES[word] }
end
它以块形式使用reduce
来查找哈希值中的每个值,并将其添加到正在运行的sum
。
这稍微多一点&#34;先进,&#34;但展示了一些其他Ruby功能:
WORD_VALUES = {
"one" => 1, "two" => 2, "three" => 3,
"four" => 4, "five" => 5, "six" => 6,
"seven" => 7, "eight" => 8, "nine" => 9
}
WORD_EXPR = /\b#{Regexp.union(WORD_VALUES.keys)}\b/
def secret_code(str)
str.scan(WORD_EXPR).reduce(0) {|sum, word| sum + WORD_VALUES[word] }
end
这使用WORD_VALUES
数组的键来构建一个看起来像(或多或少)这样的正则表达式:
WORD_EXPR = /\b(one|two|three|four|five|six|seven|eight|nine)\b/
然后它使用String#scan
,它返回与正则表达式匹配的所有子串,例如, "five monkeys in three farms".scan(WORD_EXPR)
返回["five", "three"]
。然后它使用上面的reduce
来查找它们的值并将它们相加。
答案 1 :(得分:2)
我会做这样的事情:
NUMBERS = {
'one' => 1, 'two' => 2, 'three' => 3,
'four' => 4, 'five' => 5, 'six' => 6,
'seven' => 7, 'eight' => 8, 'nine' => 9
}
def secret_code(string)
words = string.split(/\W+/)
words.inject(0) do |sum, word|
sum + NUMBERS.fetch(word, 0)
end
end
puts secret_code('one on one')
#=> 2
puts secret_code('five monkeys in three farms')
#=> 8
puts secret_code('')
#=> 0
puts secret_code('fivethreeone')
#=> 0
NUMBERS.fetch(word, 0)
尝试从NUMBERS
哈希值中获取值,如果密钥0
不存在,则返回word
。它基本上与以下相同:
if NUMBERS.key?(word)
0
else
NUMBERS[word]
end
inject(0) do |sum, word|
已使用0
初始化。它遍历数组中的每个元素,并将当前值作为sum
传递给块。块的结果(sum +
单词的值)在下一次迭代中用作sum
的新值。
答案 2 :(得分:2)
你的case语句错误,因为它包含exit
,在Ruby中导致立即终止正在运行的脚本。
您应该检查案例陈述的正确语法。
此外,您可以使用scan
快速扫描字符串以查找匹配项。
"five monkeys in three farms".scan(/five|three|four/)
=> ["five", "three"]
然后你可以将匹配转换为相应的值(例如使用存储在哈希中的地图)并计算结果。
numbers = {
"three" => 3,
"four" => 4,
"five" => 5,
}
results = "five monkeys in three farms".scan(/#{numbers.keys.join("|")}/)
=> ["five", "three"]
results.inject(0) { |total, result| total += numbers[result] }
# => 8
这个解决方案有一个警告。它将匹配部分单词,因此如果适用,您将需要使用适当的边界来调整它以考虑完整的单词(因此,如果某人可以发送类似于您在示例中提供的最后一个字符串)。
答案 3 :(得分:2)
其他人已经回答了您的代码问题。这是另一种选择。
str = "five monkeys in three farms"
h = { "one=>1", "two"=>2, "three"=>3, "four"=>4, "five"=>5,
"six"=>6, "seven"=>7, "eight"=>8, "nine"=>9 }
str.gsub(/\w+/,h).split.map(&:to_i).reduce(:+)
#=> 8
这使用采用哈希的Hash.gsub形式。步骤:
s = str.gsub(/\w+/,h)
#=> "5 3 "
不是h
键的匹配将转换为空字符串。空格与\w+/
不匹配,因此不受影响。
t = s.split
#=> ["5", "3"]
u = t.map(&:to_i)
#=> [5, 3]
u.reduce(:+)
#=> 8
答案 4 :(得分:1)
Ruby中有许多functions to search strings。您不必手动执行此操作,也不是您想要的。为此,您可以使用String#scan来查找单词。
str.scan(/(\w+)/) { |word|
... do something with word[0] ...
}
然后你需要把这些单词变成数字。 “Convert string numbers( in word format) to integer ruby”提供了几种方法。对于生产代码,您应该use a gem,但由于这是扫描字符串的练习,最简单的方法是使用一个小表。
str = "one two five and zero"
# Map words to their numbers.
word2num = {
"one" => 1, "two" => 2, "three" => 3, "four" => 4, "five" => 5,
"six" => 6, "seven" => 7, "eight" => 8, "nine" => 9, "ten" => 10,
"eleven" => 11, "twelve" => 12
};
# Because there are words which are not numbers, set the default
# for the hash to 0. If you try to put in a word that's not a
# number you'll get 0 instead of nil (which would cause an error).
word2num.default = 0
number = 0;
str.scan(/(\w+)/) { |word|
number += word2num[word[0]]
}
puts number