2016-01-18 16 views
0

我正在使用與二維數組中的第一項(從csv文件導入)匹配的ruby模塊,並返回第二項。這聽起來非常簡單,我可以讓它工作,直到我試圖匹配不在數組中的項目。當發生這種情況時,出於某種原因,整個數組被返回。我能夠制定一個解決方法,涉及一個布爾變量'found',但我想知道爲什麼這不能像書面一樣工作。在數組中搜索不存在的項返回整個數組

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 

現在,當我使用以下testfile的運行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 

I wind up wit h以下錯誤消息:

語法錯誤,意外==(SyntaxError) result = @ list.detect {| item |項| 0 | ==名} ^

然而,當我運行下面的文件,一切似乎工作,我似乎無法通過耙測試:

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

您可以通過編寫'@list.each {| item | return item.last if item.first == name}; 「錯誤」; end',但是使用'find'(又名'detect')是要走的路。 –

回答

2

您應該使用Enumerable#find代替迭代的通過與每個陣列。如果找不到該元素,則返回值將爲零。否則,您將通過查找返回它。

def self.carbs(name) 
    grams = @list.find {|item| item[0] == name} 

    if grams.nil? 
    grams = "error" 
    end 

    grams 
end 
+1

你可以進一步減少它只是'def self.carbs(name); @ list.find {| item | item [0] == name} || 「錯誤」; end';但對Geo的方法+1。 – konacaret

+0

這看起來應該工作,但我回來了:lib/nutrition1.rb:10:語法錯誤,意外的== 結果= @ list.find {| item |項| 0 | == name} ^ – AntonySerio

0

grams不會nil,即使該項目未找到。但是,如果達到了該測試,則可以確定該項目還沒有找到,因爲如果該功能找到了某些東西,該功能就已經返回。那麼在那個時候,你可以返回一個錯誤並忘記測試grams

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是一個很好的SO文章,解釋大多數種類的Ruby變量之間的差),所以它可能不會使用@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 

使用後一種選擇:

class Nutrition 
    @@list = CSV.read("./lib/list.csv") 

    def self.carbs(name) 
     return "error" if @list.nil? 
     carb = (@@list.find { |x| x[0] == name }) 
     carb.nil? ? "error" : carb[1] 
    end 
end 
+0

我不確定這是否可行。我嘗試在初始化時定義列表,但我總是用一個空數組結束。我可以構建數組的唯一方法是從初始化中取出列表。 – AntonySerio

+0

@AntonySerio我沒有看到它不應該工作的原因,但你也可以將CSV加載到類變量中。我用代碼編輯了我的答案。 – brito

0

,這並不原因按照書面的工作原則,您正在將grams分配到的返回值@listgrams = @list.each...。然後,您將在年底返回gramsreturn grams

each方法的返回值是原始陣列,如文檔中描述:http://ruby-doc.org/core-2.3.0/Array.html#method-i-each(「返回數組本身」)

在你的方法,如果發現某個項目,則提前返回將阻止最後一行運行:return item[1]