Agregue el par clave / valor al hash con << en Ruby

80

En Ruby, uno puede agregar valores a matrices existentes usando <<:

a = []
a << "foo"

pero, ¿también puede agregar pares clave / valor a un hash existente?

h = {}
h << :key "bar"

Sé que puedes hacer:

h[:key] = ""
h[:key] << "bar"

pero eso no es lo que quiero.

Gracias.

jcarpio
fuente
20
¿Por qué no h[:key] = "bar"?
Hauleth
4
Esto no funciona:h[:key] << "bar"
Chris Nielsen

Respuestas:

141

Hay merge!.

h = {}
h.merge!(key: "bar")
# => {:key=>"bar"}
sawa
fuente
3
No creo que merge!califique simplemente como la creación de un nuevo par clave / valor, ya que en realidad se usa para otro propósito.
PericlesTheo
Buen punto. Creo que también puede terminar dependiendo de otros factores que el OP no publicó.
Michael Durrant
1
Ah gracias. Parece que el método de la tienda hace algo similar. Esta fue principalmente una pregunta académica, ya que he visto << referida como una forma de agregar a matrices, pero quería ver si funcionaba para hashes. Gracias de nuevo.
jcarpio
5
La diferencia es esta: storesimplemente agrega un nuevo par, no le importa si la clave ya existe. con merge!sin embargo, las entradas con claves duplicadas son anulados por lo que el método no hace un poco más que añadir pares. Si compara los dos, encontrará storeque es más rápido (trivial, pero especialmente en pequeños hashes)
PericlesTheo
2
@jcarpio Gracias. Hash#merge!devuelve el hash del receptor al igual que Array#<<devuelve la matriz del receptor. Hash#storees algo completamente diferente. Además, con el azúcar de sintaxis hash key: "bar"en la posición del argumento, pensé que esto era lo más cerca que podía llegar a su notación. Sabía que este está más cerca de lo que querías.
sawa
89

Dado que los hash no están ordenados de forma inherente, no existe la noción de agregar. Sin embargo, los hashes de Ruby desde 1.9 mantienen el orden de inserción. Estas son las formas de agregar nuevos pares clave / valor.

La solucion mas simple es

h[:key] = "bar"

Si quieres un método, usa store:

h.store(:key, "bar")

Si realmente desea utilizar un operador de "pala" ( <<), en realidad se agrega al valor del hash como una matriz, y debe especificar la clave:

h[:key] << "bar"

Lo anterior solo funciona cuando existe la clave. Para agregar una nueva clave, debe inicializar el hash con un valor predeterminado, lo que puede hacer así:

h = Hash.new {|h, k| h[k] = ''}
h[:key] << "bar"

Es posible que tenga la tentación de parchear Hash para incluir un operador de pala que funcione de la manera que ha escrito:

class Hash
  def <<(k,v)
    self.store(k,v)
  end
end

Sin embargo, esto no hereda el "azúcar sintáctico" aplicado al operador de pala en otros contextos:

h << :key, "bar" #doesn't work
h.<< :key, "bar" #works
Mark Thomas
fuente
¡Completo! Gracias por la contribución y el conocimiento.
jcarpio
Para tener en cuenta, a partir de Ruby 1.9, los hashes están ordenados.
acero
1
Ruby 1.9+ mantiene el orden de inserción, pero un Hash como estructura de datos no tiene el concepto de ningún tipo de orden inherente.
Mark Thomas
27

No, no creo que pueda agregar pares clave / valor. Lo único más cercano que conozco es usar el storemétodo:

h = {}
h.store("key", "value")
PericlesTheo
fuente
3

¿Quizás quieres Hash # fusionar?

1.9.3p194 :015 > h={}
 => {} 
1.9.3p194 :016 > h.merge(:key => 'bar')
 => {:key=>"bar"} 
1.9.3p194 :017 > 

Si desea cambiar la matriz en su lugar, use merge!

1.9.3p194 :016 > h.merge!(:key => 'bar')
 => {:key=>"bar"} 
Michael Durrant
fuente
No creo mergeque sea una buena idea porque devuelve una nueva matriz; no agregar el nuevo par al hash existente.
PericlesTheo
¿Qué tal el merge!(es decir, a la matriz existente) en lugar de merge?
Michael Durrant
1
merge!técnicamente funciona en este contexto, pero creo que debería usarse para fusionar dos hashes en lugar de simplemente agregar un nuevo par. Además, si realiza una evaluación comparativa merge!, es más lento que store;)
PericlesTheo
3

Son similares merge!y storetratan los hashes existentes de manera diferente según los nombres de clave y, por lo tanto, afectarán sus preferencias. Aparte de eso desde el punto de vista de la sintaxis, merge!la key: "value"sintaxis coincide estrechamente con JavaScript y Python. Personalmente, siempre he odiado los pares clave-valor que separan por comas.

hash = {}
hash.merge!(key: "value")
hash.merge!(:key => "value")
puts hash

{:key=>"value"}

hash = {}
hash.store(:key, "value")
hash.store("key", "value")
puts hash

{:key=>"value", "key"=>"value"}

Para que el operador de la pala <<funcione, le aconsejaría utilizar la respuesta de Mark Thomas .

kayleeFrye_onDeck
fuente
1

Tuve que hacer algo similar, pero necesitaba agregar valores con las mismas claves. Cuando utilizo fusionar o actualizar, no puedo insertar valores con las mismas claves. Entonces tuve que usar una matriz de hashes.

    my_hash_static = {:header =>{:company => 'xx', :usercode => 'xx', :password => 'xx',
                      :type=> 'n:n', :msgheader => from}, :body=>[]}
    my_hash_dynamic = {:mp=>{:msg=>message, :no=>phones} }        
    my_hash_full = my_hash_static[:body].push my_hash_dynamic
Caner Çakmak
fuente