How to save a hash into a CSV
Solution 1
Try this:
require 'csv'
h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' }
CSV.open("data.csv", "wb") {|csv| h.to_a.each {|elem| csv << elem} }
Will result:
1.9.2-p290:~$ cat data.csv
dog,canine
cat,feline
donkey,asinine
Solution 2
If you want column headers and you have multiple hashes:
require 'csv'
hashes = [{'a' => 'aaaa', 'b' => 'bbbb'}]
column_names = hashes.first.keys
s=CSV.generate do |csv|
csv << column_names
hashes.each do |x|
csv << x.values
end
end
File.write('the_file.csv', s)
(tested on Ruby 1.9.3-p429)
Solution 3
I think the simplest solution to your original question:
def write_file
h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' }
CSV.open("data.csv", "w", headers: h.keys) do |csv|
csv << h.values
end
end
With multiple hashes that all share the same keys:
def write_file
hashes = [ { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' },
{ 'dog' => 'rover', 'cat' => 'kitty', 'donkey' => 'ass' } ]
CSV.open("data.csv", "w", headers: hashes.first.keys) do |csv|
hashes.each do |h|
csv << h.values
end
end
end
Solution 4
CSV can take a hash in any order, exclude elements, and omit a params not in the HEADERS
require "csv"
HEADERS = [
'dog',
'cat',
'donkey'
]
def write_file
CSV.open("data.csv", "wb", :headers => HEADERS, :write_headers => true) do |csv|
csv << { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' }
csv << { 'dog' => 'canine'}
csv << { 'cat' => 'feline', 'dog' => 'canine', 'donkey' => 'asinine' }
csv << { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine', 'header not provided in the options to #open' => 'not included in output' }
end
end
write_file # =>
# dog,cat,donkey
# canine,feline,asinine
# canine,,
# canine,feline,asinine
# canine,feline,asinine
This makes working with the CSV class more flexible and readable.
Solution 5
I tried the solutions here but got an incorrect result (values in wrong columns) since my source is a LDIF file that not always has all the values for a key. I ended up using the following.
First, when building up the hash I remember the keys in a separate array which I extend with the keys that are not allready there.
# building up the array of hashes
File.read(ARGV[0]).each_line do |lijn|
case
when lijn[0..2] == "dn:" # new record
record = {}
when lijn.chomp == '' # end record
if record['telephonenumber'] # valid record ?
hashes << record
keys = keys.concat(record.keys).uniq
end
when ...
end
end
The important line here is keys = keys.concat(record.keys).uniq
which extends the array of keys when new keys (headers) are found.
Now the most important: converting our hashes to a CSV
CSV.open("export.csv", "w", {headers: keys, col_sep: ";"}) do |row|
row << keys # add the headers
hashes.each do |hash|
row << hash # the whole hash, not just the array of values
end
end
![TheLegend](https://i.stack.imgur.com/sk0Hl.png?s=256&g=1)
TheLegend
#SOreadytohelp. I am a Software Developer here in Cape Town, South Africa. I mostly work on web apps, mostly in Ruby and Rails. I started back in Nov 2011. I work for a company called Peach Payments as their head of engineering. Above all else, I love simple easy to read code. I am a student of the software development process. I find the glue that holds domains together as interesting as the domains themselves.
Updated on July 09, 2022Comments
-
TheLegend almost 2 years
I am new in ruby so please forgive the noobishness.
I have a CSV with two columns. One for animal name and one for animal type. I have a hash with all the keys being animal names and the values being animal type. I would like to write the hash to the CSV without using fasterCSV. I have thought of several ideas what would be easiest.. here is the basic layout.
require "csv" def write_file h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' } CSV.open("data.csv", "wb") do |csv| csv << [???????????] end end
When I opened the file to read from it I opened it
File.open("blabla.csv", headers: true)
Would it be possible to write back to the file the same way?-
Paul Hoffer over 12 yearsJust so you know, Ruby 1.9 replaced the old CSV module with FasterCSV, so you are actually using FasterCSV. Because it is part of the Standard Library, it is called CSV instead of FasterCSV.
-
-
TheLegend over 12 yearsyeah that was the idea. convert it back to an array.. very cool thanks ! and using a block to do it plus 5 points!! high five! :)
-
Nuno Costa almost 9 yearsNone of the other answers worked for me in order to save the column headers as well. This answer works just fine
-
Ben Hull over 7 years
CSV.generate
is very handy if you don't want to actually output to a file on disk. -
s2t2 over 5 yearshow does generate compare in performance vs file writing, as the number of rows increases?
-
go2null over 5 yearsin ruby v2.5.3, at least,
write_headers: true
is required in `CSV.open