在数组中搜索不存在的项返回整个数组

时间:2016-01-18 21:53:17

标签: arrays ruby csv

我正在处理一个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

4 个答案:

答案 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