Reputation: 73
I need help understanding how to dump my hash contents into a csv. I found the following post that is exactly what I'm trying to do, but unfortunately there is no example on how to call the method so that it will write to a file.
original post Smartly converting array of hashes to CSV in ruby
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
My array of hashes is called results and looks something like this: (Note: some keys have nil values)
[{:name =>"Mike", :job = "Teacher", :status = "single"},
{:name=> "Joe", :job =>nil, :status = "married"},
{:name =>"Sally", :job = "Nurse", :status = "single"}]
I would like to dump the entire contents of the results hash into a CSV file for further manipulation. My problem is I can't figure out how to get the results into csv file. When I run:
results.to_csv
nothing happens, no file is created. I thought I may have to first seed a blank file, but even then, no contents go into the file.
Can someone please help me understand what I'm doing wrong and why this isn't working. Thanks in advance for any assistance.
Upvotes: 1
Views: 3343
Reputation: 110665
You need to define this method as an instance method of the class Array.
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
[{ :a=>1, :b=>2 }, { :c=>3 }].to_csv
#=> [{:a=>1, :b=>2}, {:c=>3}]
Let's see what was written.
CSV.read("hash.csv")
#=> [["a", "b", "c"], ["1", "2", nil], [nil, nil, "3"]]
I infer this is an array method from the code fragment
self.flat_map(&:keys)
As the mapping is to keys, it suggests that the reiceiver is an array of hashes.(That expression could have been written flat_map(&:keys)
.)
This method does not appear to meet your requirements.
You could save the keys and values thusly:
CSV.open("hash.csv", "wb") do |csv|
arr.each do |h|
csv << h
end
end
#=> [["a", "b", "c"], [1, 2, 3], [4, 5, 6]]
CSV.read("hash.csv")
#=> [["a", "b", "c"], [1, 2, 3], [4, 5, 6]]
Upvotes: 4
Reputation: 624
Try:
require 'csv'
def to_csv(csv_filename="hash.csv")
a = [{:name =>"Mike", :job => "Teacher", :status => "single"},
{:name=> "Joe", :job =>nil, :status => "married"},
{:name =>"Sally", :job => "Nurse", :status => "single"}]
values = a.map do |h|
h.sort.to_h.values
end
CSV.open(csv_filename, "wb") do |csv|
values.each do |row|
csv << row
end
end
end
Note: This works for your case, where all your columns are in the array of hashs. For example you jave "Joe" with :job
with value nil
. if this is not your case, using value_at
is the best chose
Upvotes: 0