Ruby Array #include?给出NoMethodError

时间:2012-04-20 18:09:49

标签: ruby arrays csv sakai

我有一些代码可以在继续之前检查用户是否在“sakai_trained”数组中。出于某种原因,当我运行此代码时:

CSV.foreach(activation_csv, {:headers => true}) do |row|
  if sakai_trained
    row << 'Untrained' unless sakai_trained.include?(row[1]) 
  end

  course_list << row
end

我收到此错误

C:/Ruby193/lib/ruby/1.9.1/csv.rb:478:in `==': undefined method `row' for "stuartademo":String (NoMethodError)
        from activate-courses.rb:42:in `include?'
        from activate-courses.rb:42:in `block in <main>'
        from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1792:in `each'
        from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1208:in `block in foreach'
        from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1354:in `open'
        from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1207:in `foreach'
        from activate-courses.rb:40:in `<main>'

我首先想到的是行[1]存在问题,但即使使用字符串文字也会出现相同的问题。我检查确保sakai_trained数组存在并且其中也包含数据。我也尝试将其重写为if语句,以防除非逻辑存在缺陷,但也会返回相同的错误。

如果不清楚,我想在将该行添加到course_list数组之前检查位于行[1]中的用户标识是否存在于sakai_trained数组中。如果没有,我希望首先将“未经训练”添加到行中,然后将行添加到数组中。当我删除除非...部分我能够得到一个完整的course_list数组,但正如预期的那样,每一行都有“未经训练”。问题似乎与

有关
unless sakai_trained.include?(row[1])

部分但我看不到它。

更新

sakai_trained = []
  CSV.foreach(training_csv, {:headers => true}) do |trained|
    sakai_trained << trained
  end

我应该#map!每个带有.to_s的项目,然后将它们变成字符串?

更新2:

我改变了

sakai_trained << trained

sakai_trained << trained.to_s

它删除了错误,但输出仍然不正确。

更新3: 差不多。工作。你们都非常棒,而且令人沮丧的是,我学到了一些新的有趣的东西。

代码:

course_list = []

if options[:verify]
  sakai_trained = []
  CSV.foreach(training_csv, {:headers => true}) do |trained|
    sakai_trained << trained.to_s
  end
end 

CSV.foreach(activation_csv, {:headers => true}) do |row|
  if sakai_trained && !sakai_trained.include?(row[1])  
    row << 'Untrained' 
  end

  course_list << row
end

收率:

  

2124-5318,stuartademo,未经训练

     

2124-5320,bobsmith,未经训练

     

2124-4686,jimsmith,未经训练

     

2124-3560,jillsmith,未经训练

     

2124-3562,suesmith,未经训练

     

2124-5428,harrysmith,未经训练

什么时候应该

  

2124-5318,stuartademo,未经训练

     

2124-5320,bobsmith

     

2124-4686,jimsmith

     

2124-3560,jillsmith

     

2124-3562,suesmith

     

2124-5428,harrysmith

2 个答案:

答案 0 :(得分:2)

问题发生在第478行的标准Ruby库中的csv.rb文件中。以下是导致问题的CSV代码:

#
# Returns +true+ if this row contains the same headers and fields in the
# same order as +other+.
#
def ==(other)
  @row == other.row
end

从错误消息的外观中,字符串"stuartademo"正在传递给此方法,当然,没有String#row。看起来other应该是csv文件的一行。根据上述方法的评论,它应该包含标题和字段。

我建议找到这个String "stuartademo"的来源,并找出为什么只传递String而不是整行。

编辑:

如果从CSV填充sakai_trained,则它不是数组,而是CSV:Row类型。在这种情况下,当您致电CSV::Row#include?时,==(other)即被调用。因此,您要传递的是row[1]是一个字符串。它不应该是一个字符串。

请尝试使用include?field?(data),而不是fields.include?

CSV.foreach(activation_csv, {:headers => true}) do |row|
  if sakai_trained
    row << 'Untrained' unless sakai_trained.field?(row[1]) 
  end

  course_list << row
end

答案 1 :(得分:1)

我认为这会简化逻辑,并可能帮助您以不同的方式追踪您的问题。

CSV.foreach(activation_csv, {:headers => true}) do |row|
  if sakai_trained && !sakai_trained.include?(row[1])
    row << 'Untrained'
  end

  course_list << row
end

更新:

尝试将其分解为部分并让我们知道所有输出是什么:

CSV.foreach(activation_csv, {:headers => true}) do |row|
  puts row                   #=>  2124-5318,stuartademo
  puts row.class             #=>  CSV::Row 
  puts row[1]                #=>  stuartademo 
  puts row[1].class          #=>  String 
  puts sakai_trained         #=>  I'm assuming nil because it is of NilClass
  puts sakai_trained.class   #=>  NilClass
end

我认为你的sakai_trained实际上是nil,这解释了为什么sakai_trained.to_s摆脱了错误。您无法在任何内容上调用include?,但在使用to_s时,可能会将其转换为"",这将返回false。