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. ¿Puede alguien decirme cómo hacer esto?
Estoy usando Ruby 1.9.2 si eso importa.
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. ¿Puede alguien decirme cómo hacer esto?
Estoy usando Ruby 1.9.2 si eso importa.
Respuestas:
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
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"
Haga todo lo anterior y guárdelo 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:
Creo que convertir una base de datos de registros activa a csv sería algo como esto
CSV.open(fn, 'w') do |csv|
csv << Model.column_names
Model.where(query).each do |m|
csv << m.attributes.values
end
end
Hmm @tamouse, esa esencia es algo confusa 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 debería hacer el hecho:
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á
inject
aquí, realmente quieres usar map
. Además, no necesita pasar una cadena vacía join
, ya que este es el valor predeterminado. Así que podría reducirlo aún más a esto:rows.map(&CSV.method(:generate_line).join
CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }
genera un CSV equivalente.
Si alguien está interesado, aquí hay algunas frases (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 preservar la información básica de tipo o ir a YAML detallado (pero más fácilmente editable por humanos) para preservar toda la información de tipo, por ejemplo, si necesita un tipo de fecha, que se convertiría en cadenas en CSV y JSON.
Sobre la base de la respuesta de @ boulder_ruby, esto es lo que estoy buscando, suponiendo que us_eco
contenga la tabla CSV desde 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
Se actualizó la esencia en https://gist.github.com/tamouse/4647196
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) ]
[ %w(your array), %w(goes here) ]
No se verá bonito. github.com/pry/pry/issues/568