2010-09-15 6 views
51

Ich möchte eine CSV-Datei analysieren, so dass jede Zeile wie ein Objekt behandelt wird, wobei die Kopfzeile die Namen der Attribute im Objekt ist. Ich könnte das schreiben, aber ich bin mir sicher, dass es schon da draußen ist.CSV-Datei mit Header-Feldern als Attribute für jede Zeile analysieren

Hier ist meine CSV-Eingang:

"foo","bar","baz" 
1,2,3 
"blah",7,"blam" 
4,5,6 

Der Code wie folgt aussehen würde:

CSV.open('my_file.csv','r') do |csv_obj| 
    puts csv_obj.foo #prints 1 the 1st time, "blah" 2nd time, etc 
    puts csv.bar  #prints 2 the first time, 7 the 2nd time, etc 
end 

Mit Rubys CSV-Modul Ich glaube, ich nur die Felder, die von Index zugreifen können. Ich denke, der obige Code wäre ein wenig lesbarer. Irgendwelche Ideen?

Antwort

89

Mit Ruby 1.9 und höher können Sie eine eine Wende Objekt erhalten:

CSV.foreach('my_file.csv', :headers => true) do |row| 
    puts row['foo'] # prints 1 the 1st time, "blah" 2nd time, etc 
    puts row['bar'] # prints 2 the first time, 7 the 2nd time, etc 
end 

Es ist nicht Syntax Punkt, aber es ist viel schöner als mit numerischem Indizes zu arbeiten.

Als beiseite, für Ruby 1.8.x FasterCSV ist, was Sie die obige Syntax verwenden müssen.

+0

FasterCSV wurde in Ruby integriert, ich denke, es war in Ruby 1.9+. –

25

Hier ist ein Beispiel für die symbolische Syntax mit Ruby 1.9. In den folgenden Beispielen liest der Code eine CSV-Datei namens data.csv aus dem Rails-Datenbankverzeichnis.

:headers => true behandelt die erste Zeile als Kopfzeile anstelle einer Datenzeile. :header_converters => :symbolize Parameter konvertiert dann jede Zelle in der Kopfzeile in Ruby-Symbol.

CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row| 
    puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}" 
end 

In Ruby 1,8:

require 'fastercsv' 
CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row| 
    puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}" 
end 

Auf der Grundlage der durch die Poul vorgesehen CSV (die Stackoverflow Fragesteller), die Ausgabe aus dem Beispiel oben stehenden Code wird sein:

1,2,3 
blah,7,blam 
4,5,6 

Je Bei den Zeichen, die in den Headern der CSV-Datei verwendet werden, kann es erforderlich sein, die Header auszugeben, um zu sehen, wie CSV (FasterCSV) die String-Header in Symbole konvertiert. Sie können das Array von Headern innerhalb von CSV.foreach ausgeben.

row.headers 
+0

Also habe ich CSV-Datei in ein Array mit nur 'allstocks << Zeile 'innerhalb der Schleife geladen. Wie lese ich eine Zelle "myrow [: company]" wo 'myrow [: ticker] ==" ANAD "'? Es gibt nur einen Datensatz und "Ticker" ist sowieso mein Schlüsselfeld. – Marcos

+0

Marcos - Wenn die CSV in ein Array konvertiert wurde, haben Sie möglicherweise die Hashes (Symbole) verloren. Wenn dies der Fall ist, referenziere einfach die Zelle anhand der Spaltennummer, z. Myrow [0]. – scarver2

2

Obwohl ich bin ziemlich spät, um die Diskussion, vor ein paar Monaten begann ich eine „CSV-Mapper auf Objekt“ bei https://github.com/vicentereig/virgola.

CSV-Inhalte gegeben, die Abbildung um sie zu einer Reihe von FooBar Objekte ist ziemlich einfach:

"foo","bar","baz" 
1,2,3 
"blah",7,"blam" 
4,5,6 
require 'virgola' 

class FooBar 
    include Virgola 

    attribute :foo 
    attribute :bar 
    attribute :baz 
end 

csv = <<CSV 
"foo","bar","baz" 
1,2,3 
"blah",7,"blam" 
4,5,6 
CSV 

foo_bars = FooBar.parse(csv).all 
foo_bars.each { |foo_bar| puts foo_bar.foo, foo_bar.bar, foo_bar.baz } 
+0

Gerade entdeckt, dass viele davon bereits mit den '' Load'' - und '' Dump''-Methoden (Ruby 1.9/FasterCSV) erreicht werden können https://github.com/JEG2/faster_csv/blob/master/test/tc_serialization.rb –

+0

Etwas so was. Es ist eigentlich eine ziemlich coole Funktion! https://gist.github.com/3188109 –

1

Einfach einen Hash in Ruby zu bekommen 2.3:

CSV.foreach('my_file.csv', headers: true, header_converters: :symbol) do |row| 
    puts row.to_h[:foo] 
    puts row.to_h[:bar] 
end 
0

Seit Ich habe diese Frage mit einiger Häufigkeit getroffen:

array_of_hashmaps = CSV.read("path/to/file.csv", headers: true) 
puts array_of_hashmaps.first["foo"] # 1 

Dies ist die Nicht-Block-Version, wenn Sie die gesamte Datei schlürfen möchten.