我正在处理一个ruby模块,该模块匹配二维数组中的第一项(从csv文件导入),并返回第二项。这听起来非常简单,我能够让它工作,直到我试图匹配数组中没有的项目。当发生这种情况时,由于某种原因,返回整个数组。我能够找到一个解决方案,涉及一个boolian变量',但我想知道为什么这不起作用。
require 'csv'
class Nutrition
@list = CSV.read("./lib/list.csv")
def self.carbs(name)
grams = @list.each do |item|
if item[0] == name
return item[1]
end
end
if grams == nil
grams = "error"
end
return grams
end
end
list.csv文件如下:
onion,13.75,0,0
carrot,11.375,0,0
cauliflower,19.375,0,0
cabbage,20.125,0,0
sw pepper,20,0,0
leek,7.5,0,0
mushroom,16.375,0,0
celery,33.25,0,0
apple,6.37,0,0
sweet potato,4.875,0,0
broccoli,14.8,0,0
red mill museli,1.52,0,0
mixed nuts,0,0,0.65
B. Sprouts,11,0,0
eggplant,16.66,0,0
quinoa,4.7,0,0
brown rice,4.33,0,0
sesame seed,0,0,4.5
sesame oil,0,0,4.655
pork chop,0,3.84,28.57
chick breast,0,3.22,27.77
lean turkey,0,4,100
ham,0,4.76,26.66
我编辑了原始代码如下:
require 'csv'
class Nutrition
include Enumerable
@list = CSV.read("./lib/list.csv")
def self.carbs(name)
result = @list.detect {|item| item|0| == name}
if result.nil?
result = "error"
end
result
end
end
现在,当我使用以下测试文件运行rake测试时:
require './lib/nutrition.rb'
require "test/unit"
require 'csv'
class TestNutrition < Test::Unit::TestCase
include Enumerable
def test_carbs()
assert_equal(Nutrition.carbs('onion'), "13.75")
assert_equal(Nutrition.carbs('ham'),'0')
assert_equal(Nutrition.carbs('sawdust'), 'error')
end
end
我最后收到以下错误消息:
语法错误,意外==(SyntaxError) result = @ list.detect {| item |项| 0 | ==名字} ^
然而,当我运行以下文件时,一切似乎都有效,我似乎无法通过rake测试:
require 'csv'
class Nutrition
include Enumerable
@list = CSV.read("./lib/list.csv")
def self.carbs(name)
result = @list.detect {|item| item[0] == name}
if result.nil?
result = "error"
end
result
end
end
result = Nutrition.carbs('sawdust')
puts result
答案 0 :(得分:2)
您应该使用Enumerable#find而不是使用每个迭代数组。如果未找到该元素,则返回值将为nil。否则,您将通过find返回它。
def self.carbs(name)
grams = @list.find {|item| item[0] == name}
if grams.nil?
grams = "error"
end
grams
end
答案 1 :(得分:0)
grams
也不会是nil
。但是,如果达到该测试,您可以确定无论如何都找不到该项,因为如果找到了某些内容,该函数就已经返回了。那么在那时,您可以返回错误并忘记测试grams
。
答案 2 :(得分:0)
在正确缩进代码之后,很容易理解为什么总是返回整个数组:
class Nutrition
def self.carbs(name)
grams = @list.each do |item|
if item[0] == name
return item[1]
end
end
if grams == nil
grams = "error"
end
return grams
end
end
如果name
永远不匹配,那么self.carbs
执行的最后一个语句将是return grams
,这当然会返回整个数组。
编辑此外,我建议您对设计进行一些更改。
@
个变量是实例变量(here&#39;一个很好的SO帖子,解释了大多数Ruby变量之间的差异),所以使用{{{{{{{ 1}}在一个类(即静态)方法(@list
)中。您可以将self.carbs
定义为实例方法,也可以将carbs
定义为类变量(list
)。
我使用前一个选项进行了一些重构,并用@@list
替换了每个循环:
find
使用后一种选择:
class Nutrition
def initialize
@list = CSV.read("./lib/list.csv")
end
def carbs(name)
return "error" if @list.nil?
carb = (@list.find { |x| x[0] == name })
carb.nil? ? "error" : carb[1]
end
end
答案 3 :(得分:0)
这不符合要求的原因是您要将Requested path: /
Requested path: /stylesheets/foo.css
分配给grams
each
上调用@list
的返回值。然后,您最后返回grams = @list.each...
:grams
return grams
方法的返回值是原始数组,如文档中所述:http://ruby-doc.org/core-2.3.0/Array.html#method-i-each(&#34;返回数组本身。&#34;)
在您的方法中,如果找到某个项目,则提前返回会阻止最后一行运行:each