【问题标题】:Iterating through CSV::Rows遍历 CSV::Rows
【发布时间】:2020-01-26 04:06:17
【问题描述】:

我要先说明我还在学习 ruby​​。

我正在编写一个脚本来解析 .csv 并识别数据集中可能存在的重复记录。

我有一个带有标题的 .csv 文件,所以我正在解析数据,以便我可以使用标题标题访问每一行:

@contact_table = CSV.parse(File.read("app/data/file.csv"), headers: true)

# Prints all last names in table
puts contact_table['last_name']

我正在尝试遍历表中的每一行,并确定我当前遍历的姓氏是否与下一个姓氏相似,但我在执行此操作时遇到了问题。我想我处理它的方式好像它是一个数组,但我检查了类型,它是一个 CSV::Row。

示例(这不起作用):

@contact_table.each_with_index do |c, i|
  puts "first contact is #{c['last_name']}, second contact is #{c[i + 1]['last_name']}"
end

我意识到这不是这样工作的,因为该表不是一个数组,它是一个 CSV::Row,就像我之前提到的那样。有没有什么方法可以做到这一点?我现在真的很茫然。

我的 csv 看起来像这样:

id,first_name,last_name,company,email,address1,address2,zip,city,state_long,state,phone
1,Donalt,Canter,Gottlieb Group,dcanter0@nydailynews.com,9 Homewood Alley,,50335,Des Moines,Iowa,IA,515-601-4495
2,Daphene,McArthur,"West, Schimmel and Rath",dmcarthur1@twitter.com,43 Grover Parkway,,30311,Atlanta,Georgia,GA,770-271-7837

【问题讨论】:

    标签: ruby-on-rails arrays ruby csv


    【解决方案1】:

    @contact_table 应该是 CSV::Table,它是 CSV::Rows 的集合,所以在此:

    @contact_table.each_with_index do |c, i|
      ...
    end
    

    cCSV::Row。这就是c['last_name'] 起作用的原因。问题在于:

    c[i + 1]['last_name']
    

    如果你说的是c(单行)而不是@contact_table

    @contact_table[i + 1]['last_name']
    

    然后你会得到下一个姓氏,或者当c 是最后一行时,一个例外,因为@contact_table[i+1] 将是nil

    此外,在迭代中,c当前(或(i+1)th)行,并不总是第一个。

    【讨论】:

    • 谢谢!我觉得自己太笨了,我忽略了这一点,哈哈。我的下一个问题是,当我这样做时,我得到了这个错误:没有将字符串隐式转换为这一行的整数: puts "first contact is #{c['last_name']}, second contact is #{contact_table[i + 1]['姓氏']}"。有任何想法吗?我还是有点迷茫。
    • 我一开始以为是后者。但现在我什至无法让c['last_name'] 在不引发该错误的情况下打印出任何内容。我将使用 .csv 示例更新问题。
    • 天哪!我不小心删除了headers: true。大声笑,对不起。我好累。但是,我在您的代码中添加了一个“nil:NilClass 的未定义方法 `[]'”错误。我的代码如下所示:@contact_table.each_with_index do |c, i| puts "last names are #{c['last_name']}" puts "next last name is #{@contact_table[i + 1]['last_name']}" end
    【解决方案2】:

    您对此有何用例?看起来像一个学校项目?

    我推荐for_each 而不是解析(请参阅this comparison)。我可能会为此使用Set

    • 在解析文件范围之外(即在解析代码之上)创建一个 Set。我们就叫它rows吧。
    • 在解析文件时在每次迭代期间调用rows.include?(row)
      • 如果true,那么你知道你有一个重复
      • 如果为 false,则调用 rows.add(row) 将新行添加到集合中

    您也可以只用必须不同的列(例如,row.field(:some_column_name))中的单个值填充您的集合,例如电子邮件或电话号码,并对其进行相同的包含检查。

    (如果这是一个真正的应用程序,请不要这样做。改用模型validations。)

    【讨论】:

      【解决方案3】:

      我会使用 #read 而不是 #parse 并执行以下操作:

      require 'csv'
      LASTNAME_INDEX = 2
      data = CSV.read('data.csv')
      
      data[1..-1].each_with_index do |row, index|
        puts "Contact number #{index + 1} has the following last name : #{row[LASTNAME_INDEX]}"
      end
      
      #~> Contact number 1 has the following last name : Canter
      #~> Contact number 2 has the following last name : McArthur
      

      【讨论】:

        猜你喜欢
        • 2011-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多