Arrays 检查数组x位置的元素是否等于某个值

Arrays 检查数组x位置的元素是否等于某个值,arrays,ruby,string,loops,Arrays,Ruby,String,Loops,我正在尝试创建一个以字符串作为输入的方法,如果字符串包含一、二、三、四、五、六、七、八或九,则将它们作为整数计算并相加,例如: secret_code("one on one") #=> 2 secret_code("five monkeys in three farms") #=> 8 secret_code("") #=> 0 secret_code("fivethreeone") #=> 0 我想将给定的字符串按单词拆分,并将它们放入数组中,这样我就可以迭代它,检

我正在尝试创建一个以字符串作为输入的方法,如果字符串包含一、二、三、四、五、六、七、八或九,则将它们作为整数计算并相加,例如:

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。

问题在于:

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永远不会为true,因此case语句中的任何条件都不会满足

最简单的修复方法是:

case arr[i]
  when "one"
    num += 1
  when "two"
    num += 2
  when "three"
    num += 3
  # ...
end
这段代码所做的是将arr[i]的值与1进行比较,然后再与2进行比较,依此类推,从而产生预期的行为

还要注意,我删除了exit。在Ruby中,exit退出程序。我猜您是在尝试像在其他编程语言中使用break一样使用它。这里不需要这样做,因为Ruby case语句不像某些语言中的switch语句那样有故障。在case语句中只有一个when匹配

更多改进 关于您的代码,我还有一些注释:

此代码不执行任何操作:

if !arr.any?
  0
end
你不能用0做任何事情,所以它只是消失在虚空中。您可能打算执行return0以尽早从方法返回。更好的成语应该是:

return 0 if arr.empty?
虽然在Ruby中没有必要使用EnumerableAch,但更常见的是使用EnumerableAch迭代数组的元素:

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
这将遍历单词数组,并在单词_值散列中查找每个单词。如果单词不在哈希中,它将返回默认值0

使用单词_值哈希,您还可以执行以下操作:

values = arr.map {|word| word_values[word] }
puts values.reduce(:+)
这使用map将单词数组转换为值数组,例如,三个农场中的五只猴子变为[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
在Ruby2.3中,您实际上可以执行.map和WORD_值,这非常简洁

还有另一种方法,效率稍高一些:

def secret_code(str)
  str.split(/\W+/).reduce(0) {|sum, word| sum + WORD_VALUES[word] }
end
它在其块形式中使用reduce来查找散列中的每个值,并将其添加到运行总和中

替代方案 这稍微高级一些,但展示了一些其他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/
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

然后它使用Stringscan,它返回与正则表达式匹配的所有子字符串,例如,三个农场中的五只猴子。scanWORD_EXPR返回[five,three]。然后使用上面的reduce查找它们的值并求和。

我会这样做:

WORD_EXPR = /\b(one|two|three|four|five|six|seven|eight|nine)\b/
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
尝试从数字哈希中获取值,如果关键字不存在,则返回0。它基本上与以下功能相同:

if NUMBERS.key?(word)
  0
else
  NUMBERS[word]
end

已用0初始化。它迭代数组中的每个元素,并将当前值作为和传递给块。块和的结果+字的值在下一次迭代中用作和的新值

您的case语句是错误的,因为它在Ruby中包含导致运行脚本立即终止的语句

您应该检查case语句的正确语法

此外,您可以使用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

这个解决方案有一个警告。它将匹配部分单词,因此,如果需要应用适当的边界,则需要使用它来考虑完整的单词,因此如果某人可以发送字符串,就像在示例中提供的最后一个字符串。

,代码中的问题已经被其他人回答了。这里有一个替代方案

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
它使用的是使用散列的形式。步骤如下:

s = str.gsub(/\w+/,h)
  #=> "5   3 "
非h键的匹配项将转换为空字符串。空格与\w+/不匹配,因此不受影响

t = s.split
  #=> ["5", "3"] 
u = t.map(&:to_i)
  #=> [5, 3] 
u.reduce(:+)
  #=> 8 
Ruby中有很多。你不必手动操作,而且你很难做到。对于这一点,你可以用它来寻找词语

str.scan(/(\w+)/) { |word|
    ... do something with word[0] ...
}
然后你需要把这些单词变成数字。在中提供了几种方法。对于生产代码,您应该这样做,但由于这是扫描字符串的练习,最简单的方法是使用一个小表


您的case语句似乎有一些缺陷—请看一下—不要使用exit—它将过早地退出程序。如果你解决了你的问题,摆脱了退出,你就会纠正为什么匆忙选择答案?你这样做可能会阻碍其他有趣的答案,在我看来,当你做出选择时,这对仍在研究答案的读者来说是不体谅的。许多会员在做出选择之前至少要等上几个小时,有时甚至要等上更长的时间。许多会员要等上几天。好的答案需要一段时间才能创建,而且回答的人遍布全球,或者每隔几天就会出现堆栈溢出。基本问题在重复问题的选定答案中得到回答。这个问题的其余部分是如何匹配单词来决定什么是数字单词,什么不是数字单词,这很容易通过哈希或可接受值数组来完成。对于初学者来说,这不是最容易解决的问题。你能补充一些解释吗?我同意这对初学者来说可能很难理解,详细阐述它会很有帮助,但我投+1票,因为它是一个非常聪明和漂亮的实现。但是,需要注意的是,它并不能真正回答用户在代码中遇到问题的原因;我总是试图提供解释,但有时,就像这里一样,我单独展示代码,然后编辑以提供解释。如果字符串是18只猴子,它应该返回零呢?@CarySwoveland就像我说的,在真实代码中,你会使用gem。这不是关于添加数字的问题,对于我链接到的问题,已经有一个完整的其他问题了,这是关于如何在Ruby中扫描字符串的问题。