我想将哈希映射到CSV行。
我在哈希中有几个对象:
person1 = {'first_name' => 'John', 'second_name' => 'Doe', 'favorite_color' => 'blue', 'favorite_band' => 'Backstreet Boys'}
person2 = {'first_name' => 'Susan', 'favorite_color' => 'green', 'second_name' => 'Smith'}
我想将其转换为CSV文件,其中键为列,每行为值。
我可以通过创建CSV::Row
来轻松创建标题:
h = CSV::Row.new(all_keys_as_array,[],true)
我不能依赖订单而且更重要的是,并非所有值都会一直填充。
但是当我现在尝试通过<<
和数组向表中添加行时,会忽略标题的映射。它必须是正确的顺序。
为了证明这一点,我写了这个小脚本:
require 'csv'
person1 = {'first_name' => 'John', 'second_name' => 'Doe', 'favorite_color' => 'blue', 'favorite_band' => 'Backstreet Boys'}
person2 = {'first_name' => 'Susan', 'favorite_color' => 'green', 'second_name' => 'Smith'}
persons = [person1, person2]
all_keys_as_array = %w{first_name second_name favorite_color favorite_band}
h = CSV::Row.new(all_keys_as_array,[],true)
t = CSV::Table.new([h])
persons.each do |p|
r = CSV::Row.new([],[],false)
p.each do |k, v|
r << {k => v}
end
t << r
end
puts t.to_csv
我希望这个输出:
first_name,last_name,favorite_color,favorite_band
John,Doe,blue,Backstreet Boys
Susan,Smith,green,
而是显示顺序中的值。所以输出是这样的:
first_name,second_name,favorite_color,favorite_band
John,Doe,blue,Backstreet Boys
Susan,green,Smith
最奇怪的是,当我通过['key']
查找时,我得到了正确的值:
puts "favorite_bands: #{t['favorite_band']}"
> favorite_bands: [nil, "Backstreet Boys", nil]
那么有没有办法像我期望的那样写入CSV文件?
答案 0 :(得分:5)
您可以迭代列名称
persons.each do |person|
r = CSV::Row.new([],[],false)
all_keys_as_array.each do |key|
r << person[key]
end
t << r
end
答案 1 :(得分:5)
目前的建议都有效,所以谢谢你。
然而,我使用CSV::Row#fields偶然发现了更优雅的解决方案。
然后我可以将CSV行转换为正确的数组,然后再将其添加到表中:
t << r.fields(*all_keys_as_array)
答案 2 :(得分:3)
您可以使用#to_csv
并免除所有CSV::Row
和CSV::Table
内容:
headers = %w{first_name second_name favorite_color favorite_band} # fyi if you have commas in here you'll get messed up
people = []
people << {'first_name' => 'John', 'second_name' => 'Doe', 'favorite_color' => 'blue', 'favorite_band' => 'Backstreet Boys'}
people << {'first_name' => 'Susan', 'favorite_color' => 'green', 'second_name' => 'Smith'}
require 'csv'
File.open('output.csv', 'w') do |f|
f.puts headers.to_csv
people.each do |person|
f.puts headers.map { |h| person[h] }.to_csv
end
end