60

我有一个 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],每个值都可以通过 example来访问arr[i]["time"]。我更喜欢CSVclass 而不是FasterCSVor split。你能指出方法或重定向到解决类似问题的某个线程吗?

4

7 回答 7

88

刚过headers: true

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

从那里,您可以随心所欲地操纵哈希。

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

编辑

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

于 2014-03-28T19:36:58.260 回答
42

您可以使用Ruby CSV 解析器对其进行解析,然后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) ] }
于 2013-01-07T16:26:34.743 回答
38

这是 Josh Nichols 的一篇精彩的文章,它解释了如何做你所要求的。

总而言之,这里是他的代码:

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"

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

于 2013-12-30T19:23:41.593 回答
32

更短的解决方案

解析字符串:

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

解析文件:

CSV.open(filename, headers: :first_row).map(&:to_h)
于 2018-02-26T10:08:37.637 回答
5

Nathan Long的回答略有不同

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

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

于 2016-11-18T15:48:56.510 回答
2

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

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

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

于 2018-04-24T15:39:04.330 回答
1

您也可以尝试以下宝石

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 }) 
于 2015-05-25T22:45:46.303 回答