7

我想将哈希映射到 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 文件吗?

4

3 回答 3

5

您可以迭代列名

persons.each do |person|
  r = CSV::Row.new([],[],false)
  all_keys_as_array.each do |key|
    r << person[key]
  end
  t << r
end
于 2013-03-01T16:37:10.647 回答
5

目前的建议都有效,所以谢谢你。

但是,我通过使用CSV::Row#fields偶然发现了一个更优雅的解决方案。

然后我可以在将 CSV 行添加到表之前将其转换为正确的数组:

t << r.fields(*all_keys_as_array)
于 2013-03-02T16:13:08.123 回答
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
于 2013-03-01T17:58:44.540 回答