2010-12-12 58 views
3

Dire que je dispose d'un fichier CSV avec 4 champs,Le stockage des données CSV dans hachage Ruby

ID,name,pay,age 

et environ 32000 dossiers.

Quelle est la meilleure façon de coller cela dans un hachage en Ruby?

En d'autres termes, un dossier exemple ressemblerait à ceci:

{: rec1 => {: id => "00001",: name => "Bob",: payer => 150,: age = > 95}}

Merci pour l'aide!

+0

Ce n'est pas une pratique très évolutive. Une base de données simple utilisant Postgres, MySQL ou même SQLite serait facile à construire et à utiliser avec Ruby DBI au minimum, ou un ORM comme Sequel, ActiveRecord ou Datamapper. Ils ne seront pas aussi rapides qu'un hachage en mémoire, mais ils seront plus évolutifs. –

+0

@Greg, je sais que ce n'est pas particulièrement évolutif mais comme l'ensemble de données est d'une taille relativement fixe et assez petit en ce moment, il devrait être bien. Merci pour votre solution ci-dessous, aussi :-) – mbm

+0

@mbm la meilleure façon de le faire est d'utiliser la gemme 'smarter_csv' - voir ma réponse ci-dessous – Tilo

Répondre

5

Vous pouvez utiliser le Excelsior rubygem pour cela:

csv = ... 
result = Hash.new 
counter = 1 
Excelsior::Reader.rows(csv) do |row| 
    row_hash = result[("rec#{counter}".intern)] = Hash.new 

    row.each do |col_name, col_val| 
     row_hash[col_name.intern] = col_val 
    end 
    counter += 1 
end 

# do something with result... 
+0

... Merci Jake! – mbm

+0

@mbm Vous êtes les bienvenus! xD –

+0

@JacobRelkin 'Excelsior' est sympa, mais j'aime mieux' smarter_csv' pour ses fonctionnalités. – Tilo

3

En général, nous avions envie d'utiliser un champ :id pour la clé de hachage, car ce serait la même que celle d'une clé primaire dans une table de base de données :

{"00001" => {:name => "Bob", :pay => 150, :age => 95 } } 

Cela va créer un hachage à la recherche comme ça:

require 'ap' 

# Pretend this is CSV data... 
csv = [ 
    %w[ id  name pay age ], 
    %w[ 1  bob 150 95 ], 
    %w[ 2  fred 151 90 ], 
    %w[ 3  sam 140 85 ], 
    %w[ 31999 jane 150 95 ] 

] 

# pull headers from the first record 
headers = csv.shift 

# drop the first header, which is the ID. We'll use it as the key so we won't need a name for it. 
headers.shift 

# loop over the remaining records, adding them to a hash 
data = csv.inject({}) { |h, row| h[row.shift.rjust(5, '0')] = Hash[headers.zip(row)]; h } 
ap data 

# >> { 
# >>  "00001" => { 
# >>   "name" => "bob", 
# >>   "pay" => "150", 
# >>   "age" => "95" 
# >>  }, 
# >>  "00002" => { 
# >>   "name" => "fred", 
# >>   "pay" => "151", 
# >>   "age" => "90" 
# >>  }, 
# >>  "00003" => { 
# >>   "name" => "sam", 
# >>   "pay" => "140", 
# >>   "age" => "85" 
# >>  }, 
# >>  "31999" => { 
# >>   "name" => "jane", 
# >>   "pay" => "150", 
# >>   "age" => "95" 
# >>  } 
# >> } 
1

Découvrez Ruby Gem smarter_csv, qui analyse les fichiers CSV et renvoie le (s) tableau (s) de hachage pour les lignes du fichier CSV. Il peut également faire du découpage, pour traiter plus efficacement de gros fichiers CSV, de sorte que vous pouvez passer les fragments aux travailleurs Resque parallèles ou créer des enregistrements en masse avec Mongoid ou MongoMapper.

Il est livré avec beaucoup d'options utiles - départ la documentation sur GitHub

require 'smarter_csv' 
filename = '/tmp/input.csv' 
array = SmarterCSV.process(filename) 

=> 

[ {:id=> 1, :name => "Bob", :pay => 150, :age => 95 } , 
... 
] 

Voir aussi:

0
Hash[*CSV.read(filename, :headers => true).flat_map.with_index{|r,i| ["rec#{i+1}", r.to_hash]}]