2011-11-02 34 views
6

Los nombres de los campos de mi tabla son minúsculas y los nombres de campo que obtengo de los archivos CSV son camelcase. ¿Hay alguna forma de que pueda convertir las teclas de una matriz de hashes a minúsculas?Convertir las teclas hash en minúsculas - Ruby Beginner

Aquí está el código que tengo en este momento:

CSV.foreach(file, :headers => true) do |row| 
     Users.create!(row.to_hash) 
    end 

Esto está fallando debido a que las claves son camel case (He verificado esto editando manualmente el archivo para hacer la fila de encabezado en minúsculas).

PS. Además, me gustaría saber por qué demonios, para empezar, toma en cuenta la sensibilidad a las mayúsculas de los nombres de campo de tabla.

Respuesta

11

se puede usar algo como esto:

CSV.foreach(file, :headers => true) do |row| 
    new_hash = {} 
    row.to_hash.each_pair do |k,v| 
    new_hash.merge!({k.downcase => v}) 
    end 

    Users.create!(new_hash) 
end 

no he tenido tiempo de probarlo, pero se puede tomar idea de ella.
Espero que ayude

+0

que funciona! Pero también tengo curiosidad por saber por qué los rieles diablos obligarían al caso aquí (mi sistema de archivos no distingue entre mayúsculas y minúsculas, así que ese no es el problema). – Hopstream

+0

Disculpe, pero no lo entiendo, ¿a qué se refiere con decir: Rails toma en primer lugar la sensibilidad a las mayúsculas de los nombres de campo de tablas? :) (Quizás este es mi conocimiento del inglés malo :)) – bor1s

+0

Significado de por qué los rieles requieren mayúsculas y minúsculas en la tabla para que coincidan con las claves en el hash durante la inserción – Hopstream

1

¡Agregaría el hash directamente, más eficiente que merge! porque no estás creando un hash nuevo para cada par.

CSV.foreach(file, :headers => true) do |row| 
    new_hash = {} 
    row.to_hash.each_pair do |k,v| 
    new_hash[k.downcase] = v 
    end 

    Users.create!(new_hash) 
end 
3

Ruby 1.9 proporciona una forma bastante agradable de lograr esto, utilizando each_with_object para evitar la inicialización de una variable temporal.

CSV.foreach(file, :headers => true) do |row| 
    new_hash = row.each_with_object({}) do |(k, v), h| 
    h[k.downcase] = v 
    end 

    Users.create!(new_hash) 
end 
21

Usted sólo puede utilizar la opción header_converters con CSV:

CSV.foreach(file, :headers => true, :header_converters => lambda { |h| h.try(:downcase) }) do |row| 
    Users.create!(row.to_hash) 
end 

importante poner el .try allí desde una cabecera de vacío será una excepción. Mucho mejor (y más rápido) que hacer esto en cada fila.

0

Encontré que esta solución es significativamente más rápida y un poco más "Rubyish".

CSV.foreach(file, :headers => true) do |row| 
    new_hash = Hash[row.to_hash.map { |k, v| [k.downcase, v] }] 
    Users.create!(new_hash) 
end 
+0

No estoy seguro de que sea más rubí - usa un método de clase o módulo que incluso usa un método que termina en! – shevy

2

Me parece que este enfoque más elegante:

hash_with_camelcase_keys.to_a.map { |pair| [pair.first.downcase, pair.last] }.to_h 
3

Dado que este fue etiquetado con rieles.

Con ActiveSupport que inicia vom versión 3.0 puede usar HashWithIndifferentAccess.

Eso permitirá la escritura de mayúsculas/minúsculas/símbolos para acceder a las teclas o su Hash.

my_hash = { "camelCase": "some value" } 
my_hash.with_indifferent_access[:camelcase] # 'some value' 
my_hash.with_indifferent_access['camelcase'] # 'some value' 
my_hash.with_indifferent_access['camelCase'] # 'some value' 
my_hash.with_indifferent_access['CAMELCASE'] # 'some value' 

ActiveSupport 4.0.2 también presentó la siguiente:

my_hash.deep_transform_keys!(&:downcase) 
# or if your hash isn't nested: 
my_hash.transform_keys!(&:downcase) 
+2

'with_indifferent_access' es compatible con string-or-symbol, pero * no distingue entre mayúsculas y minúsculas * para mí. ActiveSupport 5.0.4. –

Cuestiones relacionadas