2013-03-01 8 views
7

Vorrei mappare un hash a una linea CSV.Come stampare un hash su una linea CSV

Ho un paio di oggetti in un hash:

person1 = {'first_name' => 'John', 'second_name' => 'Doe', 'favorite_color' => 'blue', 'favorite_band' => 'Backstreet Boys'} 
person2 = {'first_name' => 'Susan', 'favorite_color' => 'green', 'second_name' => 'Smith'} 

voglio trasformare questo in un file CSV con i tasti come colonne ei valori per ogni riga.

posso facilmente creare le intestazioni creando una CSV::Row come questo:

h = CSV::Row.new(all_keys_as_array,[],true) 

io non posso contare su l'ordine e la più importante, non tutti i valori sono riempiti per tutto il tempo.

Ma quando ora provo ad aggiungere righe alla tabella tramite << e array, la mappatura delle intestazioni viene ignorata. Deve essere nel giusto ordine.

A dimostrazione di ciò, ho scritto questo piccolo script:

require 'csv' 

person1 = {'first_name' => 'John', 'second_name' => 'Doe', 'favorite_color' => 'blue', 'favorite_band' => 'Backstreet Boys'} 
person2 = {'first_name' => 'Susan', 'favorite_color' => 'green', 'second_name' => 'Smith'} 

persons = [person1, person2] 
all_keys_as_array = %w{first_name second_name favorite_color favorite_band} 

h = CSV::Row.new(all_keys_as_array,[],true) 
t = CSV::Table.new([h]) 

persons.each do |p| 
    r = CSV::Row.new([],[],false) 
    p.each do |k, v| 
    r << {k => v} 
    end 
    t << r 
end 

puts t.to_csv 

mi aspetterei questo output:

first_name,last_name,favorite_color,favorite_band 
John,Doe,blue,Backstreet Boys 
Susan,Smith,green, 

Invece i valori nell'ordine come appaiono. Così l'output è questo:

first_name,second_name,favorite_color,favorite_band 
John,Doe,blue,Backstreet Boys 
Susan,green,Smith 

La parte più strana è, quando faccio una ricerca tramite ['key'] ottengo i valori corretti:

puts "favorite_bands: #{t['favorite_band']}" 
> favorite_bands: [nil, "Backstreet Boys", nil] 

Quindi c'è un modo di scrivere in un file CSV come Mi aspetto?

risposta

5

I suggerimenti attuali sia il lavoro, quindi grazie per questo.

Tuttavia, mi sono imbattuto in una soluzione più elegante utilizzando CSV::Row#fields.

quindi posso solo convertire la riga CSV nella matrice corretta prima di aggiungerlo alla tabella:

t << r.fields(*all_keys_as_array) 
+0

Dove è usato lo script di dimostrazione? Non riesco a farlo funzionare. – jacobmovingfwd

+1

sostituisci "t << r" con la linea menzionata, convertirà la riga in una matrice nell'ordine corretto. Ho appena provato di nuovo e funziona. – leifg

5

Si può solo scorrere i nomi delle colonne

persons.each do |person| 
    r = CSV::Row.new([],[],false) 
    all_keys_as_array.each do |key| 
    r << person[key] 
    end 
    t << r 
end 
+0

che non risolve il problema. L'ordine è ancora imprevedibile e i valori nulli vengono ignorati. – leifg

+0

l'ordine sarebbe esattamente come definito in 'all_keys_as_array' –

+1

potresti risolvere il problema del valore nullo aggiungendo qualcosa come' persona [chiave]? persona [chiave]: '' ' –

3

Potreste essere in grado di utilizzare solo #to_csv ed erogare con tutti i CSV::Row e CSV::Table roba:

headers = %w{first_name second_name favorite_color favorite_band} # fyi if you have commas in here you'll get messed up 

people = [] 
people << {'first_name' => 'John', 'second_name' => 'Doe', 'favorite_color' => 'blue', 'favorite_band' => 'Backstreet Boys'} 
people << {'first_name' => 'Susan', 'favorite_color' => 'green', 'second_name' => 'Smith'} 

require 'csv' 
File.open('output.csv', 'w') do |f| 
    f.puts headers.to_csv 
    people.each do |person| 
    f.puts headers.map { |h| person[h] }.to_csv 
    end 
end 
+0

Buono, ma ti stai perdendo tutto lo zucchero csv usando 'File'. Prova invece 'CSV.open' e' f << headers'. – pguardiario

Problemi correlati