web-dev-qa-db-fra.com

Convertir un fichier CSV en tableau de hachages

J'ai un fichier csv, quelques statistiques de hockey, par exemple:

09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5

Je veux les enregistrer dans un tableau de hachages. Je n'ai pas d'en-tête et je voudrais ajouter des clés à chaque valeur comme "time" => "09.09.2008" etc. Chaque ligne doit être accessible comme arr[i], chaque valeur par exemple arr[i]["time"]. Je préfère la classe CSV plutôt que FasterCSV ou split. Pouvez-vous montrer le chemin ou rediriger vers un fil où un problème similaire a été résolu?

37
Mythago

Vous pouvez utiliser le analyseur Ruby CSV pour l'analyser, puis utiliser Hash[ keys.Zip(values) ] pour en faire un hachage.

Exemple:

test = '''
09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5
'''.strip

keys = ['time', etc... ]
CSV.parse(test).map {|a| Hash[ keys.Zip(a) ] }
36
AJcodez

Passez juste headers: true

CSV.foreach(data_file, headers: true) do |row|
  puts row.inspect # hash
end

De là, vous pouvez manipuler le hachage comme vous le souhaitez.

(Testé avec Ruby 2.0, mais je pense que cela a fonctionné pendant un bon moment.)

Modifier

Vous dites que vous n'avez aucun en-tête - pourriez-vous ajouter une ligne d'en-tête au début du contenu du fichier après les avoir lus?

69
Nathan Long

Ceci est un article fantastique de Josh Nichols qui explique comment faire ce que vous demandez.

Pour résumer, voici son code:

csv = CSV.new(body, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
csv.to_a.map {|row| row.to_hash }
=> [{:year=>1997, :make=>"Ford", :model=>"E350", :description=>"ac, abs, moon", :price=>3000.0}, {:year=>1999, :make=>"Chevy", :model=>"Venture \"Extended Edition\"", :description=>nil, :price=>4900.0}, {:year=>1999, :make=>"Chevy", :model=>"Venture \"Extended Edition, Very Large\"", :description=>nil, :price=>5000.0}, {:year=>1996, :make=>"Jeep", :model=>"Grand Cherokee", :description=>"MUST SELL!\nair, moon roof, loaded", :price=>4799.0}]

Vous pouvez donc enregistrer le corps de votre fichier CSV dans une chaîne appelée body.

body = "09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5"

Et puis exécutez son code comme indiqué ci-dessus.

29
CodeBiker

Une solution un peu plus courte

Analyser la chaîne:

CSV.parse(content, headers: :first_row).map(&:to_h)

Fichier d'analyse:

CSV.open(filename, headers: :first_row).map(&:to_h)
15
Pavel Evstigneev

Légère variation sur Nathan Long réponse

data_file = './sheet.csv'
data = []
CSV.foreach(data_file, headers: true) do |row|
  data << row.to_hash
end

Maintenant, data est un tableau de hachages avec lequel faire vos enchères!

5
lacostenycoder

L'option headers du module CSV accepte un tableau de chaînes à utiliser comme en-têtes, lorsqu'elles ne sont pas présentes comme première ligne dans le contenu CSV.

CSV.parse(content, headers: %w(time number team_1 team_2 score))

Cela générera un énumérable de hachages en utilisant les en-têtes donnés comme clés.

2
Will Madden

Vous pouvez également essayer le joyau suivant

require 'csv_hasher'
arr_of_hashes = CSVHasher.hashify('/path/to/csv/file')

Les clés des hachages retournés seront les valeurs d'en-tête du fichier csv.

Si vous voulez passer vos propres clés,

keys = [:key1, :key2, ... ]
arr_of_hashers = CSVHasher.hashify('/path/to/csv/file', { keys: keys }) 
1
gaurav.singharoy