2011-04-01 14 views
21

Estoy intentando construir un hash a partir de un modelo.Build hash de la colección de ActiveRecord Modelos

Este es el tipo de hash que quiero construir.

{"United Sates" => "us", "United Kingdom" => "uk" .....} 

He intentado de tantas maneras ahora que estoy dando vueltas en círculos.

Estos son solo algunos de mis pocos intentos.

select = Array.new 
countries.each do |country| 
    # select.push({country.name => country.code }) 
    # select[country.name][country.code] 
end 

h = {} 

countries.each do |c| 
    # h[] = {c.name => c.code} 
    # h[] ||= {} 
    # h[][:name] = c.name 
    # h[][:code] = c.code 
    #h[r.grouping_id][:name] = r.name 
    # h[r.grouping_id][:description] = r.description 
end 

Por favor, algunos consejos.

Gracias

+1

Algún código o incluso muéstranos lo que has intentado podría ser útil. –

+0

Usa la Fuerza ... - quiero decir simplemente usa 'pluck' y' to_h' https://stackoverflow.com/a/48836177/1536309 –

Respuesta

63

Estas son algunas de las alternativas de una sola línea:

# Ruby 2.1+ 
name_to_code = countries.map{ |c| [c.name,c.code] }.to_h 

# Ruby 1.8.7+ 
name_to_code = Hash[ countries.map{ |c| [c.name,c.code] } ] 

# Ruby 1.8.6+ 
name_to_code = Hash[ *countries.map{ |c| [c.name,c.code] }.flatten ] 

# Ruby 1.9+ 
name_to_code = {}.tap{ |h| countries.each{ |c| h[c.name] = c.code } } 

# Ruby 1.9+ 
name_to_code = countries.to_a.each_with_object({}){ |c,h| h[c.name] = c.code } 

cortesía de @ comentarios a continuación es adicto:

# Ruby 1.8+ 
name_to_code = countries.inject({}){ |r,c| r.merge c.name=>c.code } 
+0

Fantástico. Intenté el mapa sin éxito también pero con una gran lista. TY – Lee

+0

@Lee Si las opciones 'map' no funcionaron, por favor brinde detalles. Por ejemplo, ¿qué muestra 'p countries.class'? – Phrogz

+0

Una forma más compacta de hacer lo mismo --- countries.inject ({}) do | result, country | result.merge (country.name => visitor.code) final – Addicted

7

definir los países picadillo luego llenarlo de sus registros.

countries_hash = {} 
countries.each do |c| 
    countries_hash[c.name] = c.code 
end 
+0

Gracias Douglas. Construir el bloque funcionó perfecto gracias. Inyectar los errores cave me Pero sigo jugando. gracias. – Lee

+0

Se ha eliminado el ejemplo de inyectar, mi inyección-fu es obviamente débil esta tarde. –

+2

Creo que quiere que esto refuerce su inject-fu: 'countries_hash = countries.inject ({}) {| hsh, c | hsh [c.name] = c.code; hsh} '; ['inject'] (http://www.ruby-doc.org/core/classes/Enumerable.html#M001494) pasa el valor de retorno del bloque a la siguiente ronda. También está la variante ['each_with_object'] (http://www.ruby-doc.org/core/classes/Enumerable.html#M001516) de' inject' que no sufre este problema (pero tenga en cuenta el orden de los diferentes argumentos): 'countries_hash = countries.each_with_object ({}) {| c, hsh | hsh [c.name] = c.code} '. –

20

con los carriles 4 podría simplemente hacer:

country_codes = Hash[Country.pluck(:name, :code)] 

que creo que es óptimo bec ausa que no tiene que cargar un montón de objetos de campo e iterar a través de ellos

El método de desplume en los carriles 3 no permite más de un atributo, pero se podría hacer algo como:

country_codes = Hash[Country.connection.select_rows(Country.select('name, code').to_sql)] 
0

Mi respuesta favorita en estos días es utilizar pluck y to_h

countries.pluck(:name, :code).to_h 
# => {"United Sates" => "us", "United Kingdom" => "uk" .....} 

a revertirlas y tienen el código primero

countries.pluck(:code, :name).to_h 
# => {"us" => "United Sates", "uk" => "United Kingdom" .....} 
Cuestiones relacionadas