我想解析一个CSV文件,以便将每一行视为一个对象,其中header-row是对象中属性的名称。我可以写这个,但我确定它已经存在了。
这是我的CSV输入:
"foo","bar","baz"
1,2,3
"blah",7,"blam"
4,5,6
代码看起来像这样:
CSV.open('my_file.csv','r') do |csv_obj|
puts csv_obj.foo #prints 1 the 1st time, "blah" 2nd time, etc
puts csv.bar #prints 2 the first time, 7 the 2nd time, etc
end
使用Ruby的CSV模块,我相信我只能通过索引访问字段。我认为上面的代码会更具可读性。有什么想法吗?
答案 0 :(得分:109)
使用Ruby 1.9及更高版本,您可以获得一个可索引的对象:
CSV.foreach('my_file.csv', :headers => true) do |row|
puts row['foo'] # prints 1 the 1st time, "blah" 2nd time, etc
puts row['bar'] # prints 2 the first time, 7 the 2nd time, etc
end
这不是点语法,但它比数字索引更好用。
顺便说一下,对于Ruby 1.8.x FasterCSV是你需要使用上面的语法。
答案 1 :(得分:34)
以下是使用Ruby 1.9的符号语法示例。在下面的示例中,代码从Rails db目录中读取名为data.csv的CSV文件。
:headers => true
将第一行视为标题而不是数据行。然后:header_converters => :symbolize
参数将标题行中的每个单元格转换为Ruby符号。
CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row|
puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}"
end
在Ruby 1.8中:
require 'fastercsv'
CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row|
puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}"
end
根据Poul(StackOverflow提问者)提供的CSV,上面示例代码的输出将是:
1,2,3
blah,7,blam
4,5,6
根据CSV文件标题中使用的字符,可能需要输出标题以查看CSV(FasterCSV)如何将字符串标题转换为符号。您可以在CSV.foreach
。
row.headers
答案 2 :(得分:4)
在Ruby 2.3中轻松获取哈希:
CSV.foreach('my_file.csv', headers: true, header_converters: :symbol) do |row|
puts row.to_h[:foo]
puts row.to_h[:bar]
end
答案 3 :(得分:2)
虽然我讨论的时间已经很晚了,但几个月前我在https://github.com/vicentereig/virgola开始了“CSV to object mapper”。
鉴于您的CSV内容,将它们映射到FooBar
个对象的数组非常简单:
"foo","bar","baz"
1,2,3
"blah",7,"blam"
4,5,6
require 'virgola'
class FooBar
include Virgola
attribute :foo
attribute :bar
attribute :baz
end
csv = <<CSV
"foo","bar","baz"
1,2,3
"blah",7,"blam"
4,5,6
CSV
foo_bars = FooBar.parse(csv).all
foo_bars.each { |foo_bar| puts foo_bar.foo, foo_bar.bar, foo_bar.baz }
答案 4 :(得分:-1)
因为我以某种频率点击了这个问题:
array_of_hashmaps = CSV.read("path/to/file.csv", headers: true)
puts array_of_hashmaps.first["foo"] # 1
当你想要整个文件时,这是非阻止版本。