Matriz de salida a CSV en Ruby


Es bastante fácil leer un archivo CSV en una matriz con Ruby, pero no puedo encontrar ninguna buena documentación sobre cómo escribir una matriz en un archivo CSV. ¿Alguien puede decirme cómo hacer esto?

Estoy usando Ruby 1.9.2 si eso importa.

 149
Author: Jason Swett, 2011-01-28

6 answers

A un archivo:

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

A una cadena:

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

Aquí está la documentación actual sobre CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html

 267
Author: Dylan Markow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-27 22:04:37

Tengo esto en una sola línea.

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" 

Hacer todo lo anterior y guardar en un csv, en una línea.

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

NOTA:

Para convertir una base de datos active record a csv sería algo como esto Creo

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

Hmm @ tamouse, eso es algo confuso para mí sin leer la fuente csv, pero genéricamente, suponiendo que cada hash en su matriz tiene el mismo número de pares k/v y que las claves son siempre las mismas, en el mismo orden (es decir, si sus datos están estructurados), esto debe hacer la escritura:

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

Si sus datos no están estructurados, esto obviamente no funcionará

 30
Author: boulder_ruby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-10 15:01:37

Si alguien está interesado, aquí hay algunas líneas (y una nota sobre la pérdida de información de tipo en 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

Nota: CSV pierde toda la información de tipo, puede usar JSON para conservar la información de tipo básica, o ir a YAML detallado (pero más fácilmente editable por humanos) para conservar toda la información de tipo to por ejemplo, si necesita tipo de fecha, que se convertiría en cadenas en CSV y JSON.

 15
Author: Kanat Bolazar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-29 18:16:45

Si tiene una matriz de matrices de datos:

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

Entonces puedes escribir esto en un archivo con lo siguiente, que creo que es mucho más simple:

require "csv"
File.write("ss.csv", rows.map(&:to_csv).join)
 14
Author: jwadsack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-24 19:43:11

Basándome en la respuesta de @boulder_ruby, esto es lo que estoy buscando, suponiendo que us_eco contiene la tabla CSV a partir de mi esencia.

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

Actualizado el contenido esencial en https://gist.github.com/tamouse/4647196

 8
Author: tamouse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-13 17:38:11

Luchando con esto yo mismo. Esta es mi opinión:

Https://gist.github.com/2639448 :

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) ]
 2
Author: Felix Rabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-08 21:29:58