More than 1 year has passed since last update.

以下のように順番も必須項目もばらばらのハッシュ配列をCSVに変換したい.

[
    { name: "Newton", age: 84, from: "England", gender: "male" },
    { name: "Planck", age: 89, role: "physicist" },
    { from: "Russia", age: 53, name: "Tchaikovsky", role: "composer" },
    { from: "Czech", name: "Nedved", tel: "00-0000-0000", role: "soccer player" },
]

想定の変換CSV

name,age,from,gender,role,tel
Newton,84,England,male,,
Planck,89,,,physicist,
Tchaikovsky,53,Russia,,composer,
Nedved,,Czech,,soccer player,00-0000-0000

ざっと探したところ標準の方法はないみたいだったので作った.

def hash_list_to_csv_array( list, key_order=nil )
  key_order ||= list.map(&:keys).flatten.uniq
  arr = list.map do |hash|
    key_order.map{|key| hash[key]}
  end
  arr.unshift(key_order)
end

require "csv"
list = [
  { name: "Newton", age: 84, from: "England", gender: "male" },
  { name: "Planck", age: 89, role: "physicist" },
  { from: "Russia", age: 53, name: "Tchaikovsky", role: "composer" },
  { from: "Czech", name: "Nedved", tel: "00-0000-0000", role: "soccer player" },
]
puts hash_list_to_csv_array( list ).map(&:to_csv).join
  # name,age,from,gender,role,tel
  # Newton,84,England,male,,
  # Planck,89,,,physicist,
  # Tchaikovsky,53,Russia,,composer,
  # Nedved,,Czech,,soccer player,00-0000-0000

# キーの並びと項目を明示指定したいときは第2引数に指定
puts hash_list_to_csv_array( list, [:role,:name] ).map(&:to_csv).join
  # role,name
  # ,Newton
  # physicist,Planck
  # composer,Tchaikovsky
  # soccer player,Nedved

Environment

% ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]