2011-11-18 50 views
29

Soy nuevo en ruby, así que, por favor, perdona el noobishness.Cómo guardar un hash en un CSV

Tengo un CSV con dos columnas. Uno para el nombre del animal y otro para el animal. Tengo un hash con todas las claves siendo nombres de animales y los valores son de tipo animal. Me gustaría escribir el hash en el archivo CSV sin usar un CVSV más rápido. He pensado en varias ideas, ¿qué sería más fácil? Aquí está el diseño básico.

require "csv" 

def write_file 
    h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' } 

    CSV.open("data.csv", "wb") do |csv| 
    csv << [???????????] 
    end 
end 

Al abrir el archivo para leer desde que abrí File.open("blabla.csv", headers: true) ¿Sería posible volver a escribir en el archivo de la misma manera?

+0

gracias por votar sobre mi pregunta. :) – TheLegend

+3

Para que lo sepas, Ruby 1.9 reemplazó el viejo módulo CSV con FasterCSV, por lo que estás usando FasterCSV. Como es parte de la Biblioteca estándar, se llama CSV en lugar de FasterCSV. –

Respuesta

39

Prueba esto:

require 'csv' 
h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' } 
CSV.open("data.csv", "wb") {|csv| h.to_a.each {|elem| csv << elem} } 

dará como resultado:

1.9.2-p290:~$ cat data.csv 
dog,canine 
cat,feline 
donkey,asinine 
+0

Sí, esa era la idea. volver a convertirlo en una matriz ... muy buenas gracias! y usando un bloque para hacerlo más 5 puntos !! ¡Cinco altos! :) – TheLegend

+3

votaré su respuesta cuando suba. :) – TheLegend

49

Si desea encabezados de columna y tiene varios 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) 

(probado en Rubí 1.9.3- p429)

+0

Ninguna de las otras respuestas funcionó para mí para guardar los encabezados de las columnas también. Esta respuesta funciona muy bien –

+0

'CSV.generate' es muy útil si no quiere realmente salir a un archivo en el disco. – Beejamin

21

Creo que la solución más simple a su pregunta original:

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 

Con múltiples hashes que todos comparten las mismas claves:

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 
1

Traté las soluciones aquí, pero nos dieron un resultado incorrecto (valores de las columnas para mal) desde mi fuente es un archivo LDIF que no siempre tiene todos los valores para una clave. Terminé usando lo siguiente.

En primer lugar, cuando construyo el hash, recuerdo las claves en una matriz separada que extiendo con las claves que no están listadas allí.

# 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 

La línea importante aquí es keys = keys.concat(record.keys).uniq que se extiende el conjunto de teclas cuando se encuentran nuevas claves (cabeceras).

Ahora lo más importante: la conversión de nuestros valores hash a un 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 
1

Prueba esto:

require 'csv' 
data = { 'one' => '1', 'two' => '2', 'three' => '3' } 

CSV.open("data.csv", "a+") do |csv| 
     csv << data.keys 
     csv << data.values 
end 
3

CSV puede tomar un hash en cualquier orden, excluir a los elementos, y omitir un no params en la 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 

Esto hace que trabajar con la clase CSV más flexible y re adable.

0

Permite tenemos un hash,

hash_1 = {1=>{:rev=>400, :d_odr=>3}, 2=>{:rev=>4003, :d_price=>300}} 

El hash_1 anteriormente que tienen claves como algunos Identificación del 1,2, .. y los valores a los que están de nuevo hash con algunas teclas como: (rev, d_odr:,: d_price). Supongamos que queremos un archivo CSV con cabeceras,

headers = ['Designer_id','Revenue','Discount_price','Impression','Designer ODR'] 

luego hacer una nueva matriz para cada valor de hash_1 e insertarlo en el archivo CSV,

CSV.open("design_performance_data_temp.csv", "w") do |csv| 
csv << headers 
csv_data = [] 
result.each do |design_data| 
    csv_data << design_data.first 
    csv_data << design_data.second[:rev] || 0 
    csv_data << design_data.second[:d_price] || 0 
    csv_data << design_data.second[:imp] || 0 
    csv_data << design_data.second[:d_odr] || 0 
    csv << csv_data 
    csv_data = [] 
end 
end 

Ahora se están teniendo design_performance_data_temp.csv archivo guardado en su directorio correspondiente. El código anterior se puede optimizar aún más.