web-dev-qa-db-fra.com

Analyser le fichier CSV avec des champs d'en-tête comme attributs pour chaque ligne

Je voudrais analyser un fichier CSV afin que chaque ligne soit traitée comme un objet, la ligne d'en-tête étant le nom des attributs de l'objet. Je pourrais écrire ceci, mais je suis sûr que c'est déjà là.

Voici mon entrée CSV:

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

Le code ressemblerait à ceci:

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

Avec le module CSV de Ruby, je pense que je ne peux accéder aux champs que par index. Je pense que le code ci-dessus serait un peu plus lisible. Des idées?

63
Poul

En utilisant Ruby 1.9 et supérieur, vous pouvez obtenir un objet indexable:

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

Ce n'est pas de la syntaxe à points, mais c'est beaucoup plus agréable à utiliser que les index numériques.

En aparté, pour Ruby 1.8.x FasterCSV est ce dont vous avez besoin pour utiliser la syntaxe ci-dessus.

110
Peer Allan

Voici un exemple de syntaxe symbolique utilisant Ruby 1.9. Dans les exemples ci-dessous, le code lit un fichier CSV nommé data.csv dans le répertoire Rails db).

:headers => true traite la première ligne comme un en-tête au lieu d'une ligne de données. :header_converters => :symbolize paramètre convertit ensuite chaque cellule de la ligne d'en-tête en Ruby symbole.

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

Dans 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

Sur la base du CSV fourni par le Poul (le demandeur StackOverflow), la sortie de l'exemple de code ci-dessus sera:

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

En fonction des caractères utilisés dans les en-têtes du fichier CSV, il peut être nécessaire de sortir les en-têtes afin de voir comment CSV (FasterCSV) a converti les en-têtes de chaîne en symboles. Vous pouvez sortir le tableau d'en-têtes à partir de CSV.foreach.

row.headers
36
scarver2

Facile à obtenir un hachage en Ruby 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
5
Yarin

Bien que je sois assez en retard pour la discussion, il y a quelques mois, j'ai commencé un "mappeur d'objet CSV" à https://github.com/vicentereig/virgola .

Compte tenu de votre contenu CSV, le mappage vers un tableau d'objets FooBar est assez simple:

"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 }
2
Vicente Reig

Depuis que je frappe cette question avec une certaine fréquence:

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

Il s'agit de la version non bloquante, lorsque vous souhaitez Slurper le fichier entier.

0
Narfanator