【问题标题】:Duplicate header in CSV fileCSV 文件中的重复标题
【发布时间】:2015-08-10 08:23:55
【问题描述】:

我尝试使用 ruby​​ csv lib 解析 csv 文件,但该文件有两列具有相同的标题文本。是否可以访问列 :columnrow[:column_1]row[:column_2]row[:column][0]row[:column][1] 还是应该使用索引来访问它?

谢谢

【问题讨论】:

    标签: ruby csv


    【解决方案1】:

    如果您有重复的标题,那么 row[:column] 将返回第一个值。

    您必须使用索引进行迭代。

    require 'csv'
    
    filename = "/path/to/csv"
    
    csv = CSV.table(filename, {:headers => :first_row})
    headers = csv.headers
    
    csv.each_with_index do |row, i|
        (0...headers.length).each do |j|
            column_header = headers[j]
            column_value = row[j]
            puts " Row #{i}: Header '#{column_header}' has value '#{column_value}'"
        end 
    end
    

    【讨论】:

      【解决方案2】:

      你可以使用索引:

      require 'csv'
      
      data = <<data
      a,b,c,b
      1,2,3,4
      9,8,7,6
      data
      
      csv = CSV.new(data, :col_sep => ',', :headers => true)
      csv.each do |row|
        puts "b: %s, 1: %s, 3: %s" % [row['b'],row[1], row[3]]
      end
      

      注意,数字从0开始。

      您还可以使用其他方法扩展行对象:

      require 'csv'
      
      class CSV::Row
        def b_1; self[1]; end
        def b_2; self[3]; end
      end
      
      data = <<data
      a,b,c,b
      1,2,3,4
      9,8,7,6
      data
      csv = CSV.new(data, :col_sep => ',', :headers => true)
      csv.each do |row|
        puts row.b_1
        puts row.b_2
      end
      

      此逻辑将定义方法 b_1b_2 用于所有行对象(也用于完全不同的 CSV 文件)。所以这可能是一个小脚本的解决方案,但我不会在更大的项目中使用它。

      您也可以在每个循环中临时定义该方法:

      require 'csv'
      
      data = <<data
      a,b,c,b
      1,2,3,4
      9,8,7,6
      data
      csv = CSV.new(data, :col_sep => ',', :headers => true)
      csv.each do |row|
        class << row
          def b_1; self[1]; end
          def b_2; self[3]; end
        end
        puts row.b_1
        puts row.b_2
      end
      

      如果您有多个循环,您还可以定义一个模块并扩展每一行:

      require 'csv'
      
      module RowExtension
        def b_1; self[1]; end
        def b_2; self[3]; end
      end
      
      data = <<data
      a,b,c,b
      1,2,3,4
      9,8,7,6
      data
      csv = CSV.new(data, :col_sep => ',', :headers => true)
      csv.each do |row|
        row.extend RowExtension
        puts row.b_1
        puts row.b_2
      end
      

      也许还可以扩展 CSV 类以返回特定的行元素。但这超出了我的实际知识范围。


      另一个解决方案是使用 headers-option。 headers-options 定义了标题字段,因此您可以定义自己的标题:

      require 'csv'
      
      data = <<data
      a,b,c,b
      1,2,3,4
      9,8,7,6
      data
      csv = CSV.new(data, :col_sep => ',', :headers => %w{a b_1 c b_2})
      csv.each do |row|
        puts row['b_1']
        puts row['b_2']
      end
      

      现在您必须忽略第一行(旧标题行)。

      【讨论】:

      • 今天找到了这个答案,寻找解决类似问题的最佳方法,我很惊讶地看到没有人支持。使用模块扩展行非常聪明!谢谢。
      【解决方案3】:

      我不确定你的问题。但是如果您想以表格格式访问您的 CSV 数据,只需使用 CSV::Table 类,如下所示

      csv = CSV.table(filename)
      

      Here 是关于方法的更多信息

      如果你想在解析数据后以列为单位访问你的数据,只需将数组转置如下

      csv = CSV.parse('csv_string')
      csv_array = csv.transpose 
      

      【讨论】:

        猜你喜欢
        • 2021-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-31
        • 2010-12-16
        • 1970-01-01
        • 2017-12-26
        相关资源
        最近更新 更多