Output array to CSV in Ruby

It's easy enough to read a CSV file into an array with Ruby but I can't find any good documentation on how to write an array into a CSV file. Can anyone tell me how to do this?

I'm using Ruby 1.9.2 if that matters.

4

6 Answers

To a file:

require 'csv' CSV.open("myfile.csv", "w") do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end 

To a string:

require 'csv' csv_string = CSV.generate do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end 

Here's the current documentation on CSV: (until 3.1.1 just replace 1.9.2)

while 3.1.2 up to latest (3.2.2 as of this edit).

3

If you have an array of arrays of data:

rows = [["a1", "a2", "a3"],["b1", "b2", "b3", "b4"], ["c1", "c2", "c3"]] 

Then you can write this to a file with the following, which I think is much simpler:

require "csv" File.write("ss.csv", rows.map(&:to_csv).join) 
2

I've got this down to just one line.

rows = [['a1', 'a2', 'a3'],['b1', 'b2', 'b3', 'b4'], ['c1', 'c2', 'c3'], ... ] csv_str = rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join("") #=> "a1,a2,a3\nb1,b2,b3\nc1,c2,c3\n" 

Do all of the above and save to a csv, in one line.

File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join(""))} 

NOTE:

To convert an active record database to csv would be something like this I think

CSV.open(fn, 'w') do |csv| csv << Model.column_names Model.where(query).each do |m| csv << m.attributes.values end end 

Hmm @tamouse, that gist is somewhat confusing to me without reading the csv source, but generically, assuming each hash in your array has the same number of k/v pairs & that the keys are always the same, in the same order (i.e. if your data is structured), this should do the deed:

rowid = 0 CSV.open(fn, 'w') do |csv| hsh_ary.each do |hsh| rowid += 1 if rowid == 1 csv << hsh.keys# adding header row (column labels) else csv << hsh.values end# of if/else inside hsh end# of hsh's (rows) end# of csv open 

If your data isn't structured this obviously won't work

6

If anyone is interested, here are some one-liners (and a note on loss of type information in CSV):

require 'csv' rows = [[1,2,3],[4,5]] # [[1, 2, 3], [4, 5]] # To CSV string csv = rows.map(&:to_csv).join # "1,2,3\n4,5\n" # ... and back, as String[][] rows2 = csv.split("\n").map(&:parse_csv) # [["1", "2", "3"], ["4", "5"]] # File I/O: filename = '/tmp/vsc.csv' # Save to file -- answer to your question IO.write(filename, rows.map(&:to_csv).join) # Read from file # rows3 = IO.read(filename).split("\n").map(&:parse_csv) rows3 = CSV.read(filename) rows3 == rows2 # true rows3 == rows # false 

Note: CSV loses all type information, you can use JSON to preserve basic type information, or go to verbose (but more easily human-editable) YAML to preserve all type information -- for example, if you need date type, which would become strings in CSV & JSON.

Building on @boulder_ruby's answer, this is what I'm looking for, assuming us_eco contains the CSV table as from my gist.

CSV.open('outfile.txt','wb', col_sep: "\t") do |csvfile| csvfile << us_eco.first.keys us_eco.each do |row| csvfile << row.values end end 

Updated the gist at

Struggling with this myself. This is my take:

:

require 'csv' class CSV def CSV.unparse array CSV.generate do |csv| array.each { |i| csv << i } end end end CSV.unparse [ %w(your array), %w(goes here) ] 
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like