将 CSV 文件转换为哈希数组

Posted

技术标签:

【中文标题】将 CSV 文件转换为哈希数组【英文标题】:Convert CSV file into array of hashes 【发布时间】: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)"],[下一行...] 【参考方案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 ) 

【讨论】:

以上是关于将 CSV 文件转换为哈希数组的主要内容,如果未能解决你的问题,请参考以下文章

将带有标题的CSV转换为哈希数组

csv转换obj

如何将csv文件转换为numpy数组格式?

将CSV文件转换为Python字典,数组和二进制文件

为啥将 numpy 数组转换为 csv 文件不显示属性名称,而是将第一行值作为属性名称?

将嵌套的 JSON 数组转换为 CSV 文件中的单独列