2010-12-10 15 views
31

Estoy tratando de inicializar un hash de matrices tales como¿Cómo puedo inicializar una matriz dentro de un hash en Ruby

@my_hash = Hash.new(Array.new) 

de manera que pueda:

@my_hash["hello"].push("in the street") 
=> ["in the street"] 
@my_hash["hello"].push("at home") 
=> ["in the street", "at home"] 
@my_hash["hello"] 
=>["in the street", "at home"] 

El problema es que cualquier nueva clave hash también vuelven ["in the street", "at home"]

@my_hash["bye"] 
=> ["in the street", "at home"] 
@my_hash["xxx"] 
=> ["in the street", "at home"] 

!!! ???

¿Qué estoy haciendo mal cuál sería la forma correcta de inicializar un Hash of Arrays?

+0

relacionada: http://stackoverflow.com/questions/190740/setting-ruby-hash-default-to-a-list – tokland

Respuesta

83
@my_hash = Hash.new(Array.new) 

Esto crea exactamente un objeto de matriz, que se devuelve cada vez que no se encuentra una llave. Como solo mutes esa matriz y nunca creas una nueva, todas tus claves se asignan a la misma matriz.

Lo que se quiere hacer es:

@my_hash = Hash.new {|h,k| h[k] = Array.new } 

o simplemente

@my_hash = Hash.new {|h,k| h[k] = [] } 

Pasando un bloque a Hash.new difiere de pasar simplemente un argumento de 2 maneras:

  1. El el bloqueo se ejecuta cada vez que no se encuentra una clave. Por lo tanto, obtendrás una nueva matriz cada vez. En la versión con un argumento, ese argumento se evalúa una vez (antes de llamar al new) y el resultado de eso se devuelve cada vez.

  2. Al hacer h[k] =, realmente inserta la clave en el hash. Si no lo hace, solo acceda a @my_hash[some_key] y no hará que some_key se inserte en el hash.

+14

El Gotcha a tener en cuenta aquí es que ahora incluso comprobación * * una clave lo creará, que puede no ser lo que quieres. Por esta razón, a veces creo Hash normalmente (con solo {}) y luego hago la creación de matriz en la llamada, como '(@myhash [" hello "] || = []). Push (" en la calle ") ")'. –

2

El argumento para Hash.new es para el valor predeterminado para las nuevas claves hash, por lo que cuando se pasa una referencia esa referencia se utilizará para las nuevas claves hash. Está actualizando esa referencia cuando se llama ...

hash["key"].push "value" 

Es necesario aprobar una nueva referencia en la tecla de almohadilla antes de empujar a los valores que ...

hash["key1"] = Array.new 
hash["key1"].push "value1" 
hash["key2"] = Array.new 
hash["key2"].push "value2 

Usted podría tratar de encapsular esta en un método auxiliar también.

7

Prueba esto:

@my_hash = Hash.new { |h, k| h[k] = Array.new } 
Cuestiones relacionadas