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?
La respuesta que tiene es excelente, pero permítame recomendarle que no use CSV. Si no tiene pestañas en sus datos, los archivos delimitados por pestañas son mucho más fáciles de manejar porque no implican tanto citas y escapes. Si debe usar CSV, por supuesto, son los descansos.
Bill Dueber
8
@Bill, el módulo CSV maneja perfectamente los archivos delimitados por tabulaciones, así como los archivos csv reales. La opción: col_sep le permite especificar el separador de columna como "\ t" y todo está bien.
@David es el modo de archivo. "w" significa escribir en un archivo. Si no especifica esto, el valor predeterminado será "rb" (modo binario de solo lectura) y obtendrá un error al intentar agregar a su archivo csv. Consulte ruby-doc.org/core-1.9.3/IO.html para obtener una lista de los modos de archivo válidos en Ruby.
Dylan Markow
15
Gotcha Y para futuros usuarios, si desea que cada iteración no sobrescriba el archivo csv anterior, use la opción "ab".
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 +=1if rowid ==1
csv << hsh.keys# adding header row (column labels)else
csv << hsh.valuesend# of if/else inside hshend# of hsh's (rows)end# of csv open
Si sus datos no están estructurados, esto obviamente no funcionará
Extraje un archivo CSV usando CSV.table, hice algunas manipulaciones, me deshice de algunas columnas, y ahora quiero poner en cola la matriz resultante de Hashes nuevamente como CSV (realmente delimitado por tabulaciones). ¿Cómo? gist.github.com/4647196
tamouse
hmm ... esa esencia es algo opaca, pero dada una serie de hashes, todos con el mismo número de pares k / v y las mismas teclas, en el mismo orden ...
boulder_ruby
Gracias, @boulder_ruby. Que funcionará. Los datos son una tabla censal, y esa esencia es bastante opaca si la miramos de nuevo. :) Básicamente está extrayendo ciertas columnas de la tabla censal original en un subconjunto.
tamouse
3
Estás haciendo mal uso injectaquí, 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
iGEL
1
Su segundo ejemplo es demasiado complicado, ya que la biblioteca CSV es bastante poderosa. 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.
Por cierto, tenga cuidado con las matrices multidimensionales en palanca en JRuby. [ %w(your array), %w(goes here) ]No se verá bonito. github.com/pry/pry/issues/568
Respuestas:
A un archivo:
A una cadena:
Aquí está la documentación actual sobre CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html
fuente
Tengo esto en una sola línea.
Haga todo lo anterior y guárdelo en un csv, en una línea.
NOTA:
Creo que convertir una base de datos de registros activa a csv sería algo como esto
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:
Si sus datos no están estructurados, esto obviamente no funcionará
fuente
inject
aquí, realmente quieres usarmap
. Además, no necesita pasar una cadena vacíajoin
, 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 tiene una matriz de matrices de datos:
Luego puede escribir esto en un archivo con lo siguiente, que creo que es mucho más simple:
fuente
Si alguien está interesado, aquí hay algunas frases (y una nota sobre la pérdida de información de tipo en CSV):
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.
fuente
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.Se actualizó la esencia en https://gist.github.com/tamouse/4647196
fuente
Luchando con esto yo mismo. Esta es mi opinión:
https://gist.github.com/2639448 :
fuente
[ %w(your array), %w(goes here) ]
No se verá bonito. github.com/pry/pry/issues/568