【问题标题】:Ruby Array#include? giving NoMethodErrorRuby 数组#include?给出 NoMethodError
【发布时间】:2012-05-02 08:07:33
【问题描述】:

我有一些代码在继续之前检查用户是否在“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>'

起初我以为 row[1] 有问题,但即使使用字符串文字也会以相同的方式中断。我检查以确保 sakai_trained 数组存在并且其中也有数据。我还尝试将其重写为 if 语句,以防除非逻辑有缺陷,但也会返回相同的错误。

如果不清楚,我想在将行添加到 course_list 数组之前检查位于 row[1] 中的用户 ID 是否存在于 sakai_trained 数组中。如果没有,我希望先将“未训练”添加到行中,然后将行添加到数组中。当我删除 unless... 部分时,我能够获得一个完整的 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,鲍勃史密斯,未受过训练

2124-4686,吉姆史密斯,未受过训练

2124-3560,吉尔史密斯,未受过训练

2124-3562,苏史密斯,未受过训练

2124-5428,哈里史密斯,未受过训练

应该是什么时候

2124-5318,stuartademo,未受过训练

2124-5320,鲍勃史密斯

2124-4686,吉姆史密斯

2124-3560,吉尔史密斯

2124-3562,苏史密斯

2124-5428,哈里史密斯

【问题讨论】:

  • 这个错误没有意义。第 478 行是哪一行?
  • 错误来自 csv.rb,它是标准 ruby​​ 库的一部分,而不是我的代码的一部分,如 below. 所示,我同意,这没有任何意义。 -_-
  • 向我们展示设置 sakai_trained 的代码。我怀疑填充到其中的对象不是字符串,而是CSV::Rows,这就解释了为什么 Array#include?正在评估CSV::Row#==
  • 我不知道 csv 行没有作为字符串读入数组。我已经用相关行更新了上面的帖子。

标签: ruby arrays csv sakai


【解决方案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 摆脱了错误。您不能在任何 nil 上调用 include?,但是当您使用 to_s 时,它可能会将其变成 "",这将返回 false。

【讨论】:

  • 试过了,它抛出了完全相同的错误。根据我的经验和测试#include?接受一个字符串,但由于某种原因,在这个 csv#foreach 循环中它需要一行。不过我喜欢逻辑上的简化。
  • 您在询问 ruby​​ sakai_trained(some object) 是否包含字符串。您可以检查一个特定属性而不是整个对象吗?还是 sakai_trained 已经是一个字符串了?
  • sakai_trained 是一个数组,我认为它充满了从不同的 CSV 读取的字符串(如现在在原始更新帖子中所述)。
  • 尝试运行我更新的代码,看看所有不同的部分会非常有益。
  • 2124-5318,stuartademo CSV::Row stuartademo String NilClass 2124-5320,littletw CSV::Row bobsmith String NilClass 2124-4686,ossmerm CSV::Row jimsmith String NilClass 2124-3560,manzuetac CSV ::Row tomsmith String NilClass 2124-3562,manzuetac CSV::Row jillsmith String NilClass 2124-5428,pleasantsg CSV::Row lovelysg String NilClass 是你代码的输出,但是注意我更新了sakai_trained代码添加了trained.to_s而不是 CSV 行。
【解决方案2】:

问题出现在标准 Ruby 库中第 478 行的 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 文件的一行。根据上面方法的cmets,应该包含headers和fields。

我建议找到这个字符串"stuartademo" 的来源,并找出为什么只有字符串而不是整行被传入。

编辑:

如果 sakai_trained 是从 CSV 填充的,则它不是数组而是 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

【讨论】:

  • 这是因为我通过 row[1] 包含?并且 row[1] 是一个字符串。这不是重点吗?查看一个字符串是否在数组中?如果我传递整个数组,代码会运行,但条件永远不会为真,因为 sakai_trained 数组不包含 activation_csv 数组中的任何整行。
  • include? 方法中发生错误是没有意义的(即使这是错误消息所说的),因为include? 方法永远不会调用@ 987654339@ 文件。让我仔细看看csv.rb 文件。
  • 我正在寻找和寻找,我似乎无法找到调用 ==(other) 的任何地方,但这绝对是导致错误的原因。 Array#include?CSV::Row#&lt;&lt;(arg)CSV::Row#field(header_or_index, minimum_index = 0) 都被调用,但没有一个调用 ==(other)。 =\
  • 从 csv 文件中填充的 sakai_trained 更新更有意义。这就是==(other) 被调用的地方。我已经更新了我的答案以反映这一点。
  • @thekungfuman 您的 training_csv 文件中的一行是什么样的?您现在正在调用 #to_s,但如果它有字段,并且您只测试一个字段,则需要提取该字段并将其字符串表示形式推送到 sakai_trained。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
相关资源
最近更新 更多