【问题标题】:Convert CSV file into array of hashes将 CSV 文件转换为哈希数组
【发布时间】:2012-12-21 09:48:26
【问题描述】:

我有一个 csv 文件,一些曲棍球数据,例如:

09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5

我想将它们保存在哈希数组中。我没有任何标题,我想为每个值添加键,例如 "time" => "09.09.2008" 等等。每一行都应该可以通过arr[i] 来访问,每个值可以通过例如arr[i]["time"] 来访问。我更喜欢CSV 类而不是FasterCSVsplit。你能指出方法或重定向到解决类似问题的某个线程吗?

【问题讨论】:

  • 什么是so on?除了"time",我们不知道你想要什么键。也许你应该显示预期的输出。
  • 等等..我的意思是等等,我的英语可能不太好。其他关键可能是回合、主队和客队以及得分。预期输出为 {["time" => "09.09.2008", "round" => "1", "home" => "Vitkovice Steel", "visiting" => "BK Mlada Boleslav", "score" = > "1:0 (PP)"],[下一行...]}

标签: ruby csv multidimensional-array


【解决方案1】:

只要通过headers: true

CSV.foreach(data_file, headers: true) do |row|
  puts row.inspect # hash
end

从那里,您可以随意操作散列。

(使用 Ruby 2.0 测试,但我认为这已经工作了很长时间。)

编辑

您说您没有任何标题 - 您可以在阅读文件内容后在文件内容的开头添加标题行吗?

【讨论】:

  • 从技术上讲,我认为每一行都是CSV::Row 的一个实例,它的作用类似于Hash,但实际上并不继承Hash
  • 你也可以使用CSV.parse(data, headers: true).map(&:to_h) 来达到类似的效果,考虑到上面 Jared 的注释。这会将您的 CSV 转换为以标题为键的哈希数组。您还可以加入选项header_converters: :symbol 以使用符号作为键而不是列名作为字符串。
【解决方案2】:

您可以使用Ruby CSV parser 对其进行解析,然后使用Hash[ keys.zip(values) ] 使其成为哈希。

例子:

test = '''
09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5
'''.strip

keys = ['time', etc... ]
CSV.parse(test).map {|a| Hash[ keys.zip(a) ] }

【讨论】:

  • 我试过 'require 'csv' csv_data = CSV.read 'data.txt' keys = ['time',"round","home","visiting","score"] CSV .parse(csv_data).map {|a| Hash[ keys.zip(a) ] }' 但我可能没有抓住这个想法,因为它返回了一些错误
  • c:/Ruby193/lib/ruby/1.9.1/csv.rb:1381:in ensure in parse': undefined method close' for #<0x8f2050>
【解决方案3】:

这是 Josh Nichols 的 fantastic post,它解释了如何按照您的要求进行操作。

总结一下,这里是他的代码:

csv = CSV.new(body, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
csv.to_a.map {|row| row.to_hash }
=> [{:year=>1997, :make=>"Ford", :model=>"E350", :description=>"ac, abs, moon", :price=>3000.0}, {:year=>1999, :make=>"Chevy", :model=>"Venture \"Extended Edition\"", :description=>nil, :price=>4900.0}, {:year=>1999, :make=>"Chevy", :model=>"Venture \"Extended Edition, Very Large\"", :description=>nil, :price=>5000.0}, {:year=>1996, :make=>"Jeep", :model=>"Grand Cherokee", :description=>"MUST SELL!\nair, moon roof, loaded", :price=>4799.0}]

因此,您可以将 CSV 文件的正文保存到名为 body 的字符串中。

body = "09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5"

然后运行他上面列出的代码就可以了。

【讨论】:

  • 感谢帖子参考,很有用。我不确定这是否是我的数据;但是,我需要省略 :blank_to_nil 否则我会收到错误 *** NoMethodError Exception: undefined method arity' for nil:NilClass`
  • @CodeBiker @shakerlxxv 我有同样的错误信息,NoMethodError: undefined method encode for nil:Nilclass。有什么办法让它工作?
  • @user2012677,我省略了:blank_to_nil转换器,所以我的最终表达式看起来像CSV.new(File.new(file), :headers =&gt; true, :header_converters =&gt; :symbol, :converters =&gt; [:all]).to_a.map {|row| row.to_hash }
  • 您也可以将其简化为:CSV.new(body, headers: true).map(&amp;:to_hash)(至少在 Ruby 2.1.5 中)
  • 我更喜欢上面 Pavel 的解决方案
【解决方案4】:

稍微短一点的解决方案

解析字符串:

CSV.parse(content, headers: :first_row).map(&:to_h)

解析文件:

CSV.open(filename, headers: :first_row).map(&:to_h)

【讨论】:

  • 解析文件代码导致:/usr/lib/ruby/2.5.0/csv.rb:1764:in to_h': Error element type String at 0 (expected array) (TypeError)`
【解决方案5】:

Nathan Long 的回答略有不同

data_file = './sheet.csv'
data = []
CSV.foreach(data_file, headers: true) do |row|
  data << row.to_hash
end

现在data 是一个哈希数组供您竞标!

【讨论】:

  • 更精简:data = CSV.foreach(data_file, headers: true).map{ |row| row.to_h }
【解决方案6】:

CSV 模块的 headers 选项接受一个字符串数组作为标题,当它们不作为 CSV 内容的第一行出现时。

CSV.parse(content, headers: %w(time number team_1 team_2 score))

这将使用给定的标头作为键生成可枚举的哈希。

【讨论】:

    【解决方案7】:

    你也可以试试下面的 gem

    require 'csv_hasher'
    arr_of_hashes = CSVHasher.hashify('/path/to/csv/file')
    

    返回的哈希键将是 csv 文件的标头值。

    如果你想传递自己的密钥,那么

    keys = [:key1, :key2, ... ]
    arr_of_hashers = CSVHasher.hashify('/path/to/csv/file', { keys: keys }) 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-30
      • 2019-10-27
      • 2019-05-23
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      相关资源
      最近更新 更多