I need to convert an array of hashes in a CSV file. The various methods I found involve inserting in the array the hash values:
class Array
def to_csv(csv_filename="hash.csv")
require 'csv'
CSV.open(csv_filename, "wb") do |csv|
csv << first.keys # adds the attributes name on the first line
self.each do |hash|
csv << hash.values
end
end
end
end
Unfortunately this method requires that each element in the array is complete, for example when I have this array it won't even return a valid csv:
myarray = [
{foo: 1, bar: 2, baz: 3},
{bar: 2, baz: 3},
{foo: 2, bar: 4, baz: 9, zab: 44}
]
I'm looking for a way to create a csv that finds all the possible headers, and assigns the values in correct order, adding empty spaces where needed.
What about:
class Array
def to_csv(csv_filename="hash.csv")
require 'csv'
# Get all unique keys into an array:
keys = self.flat_map(&:keys).uniq
CSV.open(csv_filename, "wb") do |csv|
csv << keys
self.each do |hash|
# fetch values at keys location, inserting null if not found.
csv << hash.values_at(*keys)
end
end
end
end
I would do it in this way. It's quite brute force because it needs to find all the headers that exist and also needs to fill the empty elements..
class Array
def to_csv(csv_filename='test.csv')
require 'csv'
headers = []
self.each {|hash| headers += hash.keys}
headers = headers.uniq
rows = []
self.each do |hash|
arr_row = []
headers.each {|header| arr_row.push(hash.key?(header) ? hash[header] : nil)}
csv_row = CSV::Row.new(headers, arr_row)
rows.push(csv_row)
end
csv_table = CSV::Table.new(rows)
File.open(csv_filename, 'w'){|file| file << csv_table.to_s}
end
end
Take a look at CSV::Row and CSV::Table classes. I find them handy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With