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

时间:2015-12-11 18:37:44

标签: arrays ruby string loops

我尝试创建一个将字符串作为输入的方法,如果该字符串包含onetwothreefour,{ {1}},fivesixseveneight将它们计为整数并添加它们,例如:

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

5 个答案:

答案 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"会返回truefalse,而true === arrfalse === 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匹配。

更多改进

我的代码还有一些注意事项:

  1. 此代码无法执行任何操作:

    case

    你不能对if !arr.any? 0 end 做任何事情,所以它就会消失在虚空之中。您可能希望尽早从方法返回0。一个更好的习语就是这样:

    return 0
  2. 这里不需要
  3. return 0 if arr.empty? 在Ruby中,使用while来迭代数组的元素会更常见:

    Enumerable#each
  4. 通过将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
    
  5. 您可以使用哈希而不是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

  6. 使用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)来计算值的总和。

  7. 现在一起

    将所有这些改进放在一起,我们有:

    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