ruby - ¿Cómo asignar el hash[''a''][''b'']=''c'' si el hash[''a''] no existe?
variable-assignment autovivification (5)
¿Hay alguna manera más simple que
if hash.key?(''a'')
hash[''a''][''b''] = ''c''
else
hash[''a''] = {}
hash[''a''][''b''] = ''c''
end
La forma más fácil es construir su Hash con un argumento de bloque:
hash = Hash.new { |h, k| h[k] = { } }
hash[''a''][''b''] = 1
hash[''a''][''c''] = 1
hash[''b''][''c''] = 1
puts hash.inspect
# "{"a"=>{"b"=>1, "c"=>1}, "b"=>{"c"=>1}}"
Este formulario para new
crea un nuevo valor de hash vacío como valor predeterminado. Usted no quiere esto:
hash = Hash.new({ })
ya que utilizará exactamente el mismo hash para todas las entradas predeterminadas.
Además, como señala Phrogz, puede hacer que los hash vivificados automáticamente se vivifiquen utilizando default_proc
:
hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
ACTUALIZACIÓN : Creo que debería aclarar mi advertencia contra Hash.new({ })
. Cuando dices esto:
h = Hash.new({ })
Eso es muy parecido a decir esto:
h = Hash.new
h.default = { }
Y luego, cuando accede a h
para asignar algo como h[:k][:m] = y
, se comporta como si hiciera esto:
if(h.has_key?(:k))
h[:k][:m] = y
else
h.default[:m] = y
end
Y luego, si h[:k2][:n] = z
, terminarás asignando h.default[:n] = z
. Tenga en cuenta que h
todavía dice que h.has_key?(:k)
es falso.
Sin embargo, cuando dices esto:
h = Hash.new(0)
Todo saldrá bien porque nunca modificará h[k]
aquí, solo leerá un valor de h
(que usará el valor predeterminado si es necesario) o asignará un nuevo valor a h
.
La pregunta aquí: ¿Es posible la autoinicialización de un conjunto de hash multidimensional en Ruby, como lo es en PHP? proporciona una implementación de AutoHash
muy útil que hace esto.
Si crea un hash
como el siguiente, con el valor predeterminado de un nuevo hash (idénticamente con un valor predeterminado): (gracias a Phrogz por la corrección; tuve la sintaxis incorrecta)
hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
Entonces puedes hacer
hash["a"]["b"] = "c"
sin ningún código adicional.
Uno simple, pero el hash debería ser un objeto hash válido.
(hash["a"] ||= {})[''b''] = "c"
class NilClass
def [](other)
nil
end
end
Una vez que hayas definido eso, todo funcionará automáticamente. Pero tenga en cuenta que de ahora en adelante nil
se comportaría como un hash vacío cuando se usara como un hash.