2011-03-30 11 views
8

Estaba agregando elementos a una tecla Hash. Esperaba obtener una estructura como esta:¿No se puede usar una matriz como valores predeterminados para Ruby Hash?

{ 
    'a' : [1], 
    'b' : [2, 3, 4] 
} 

Usé una matriz para inicializar la Hash.

irb> hash = Hash.new([]) 
=> {} 

Entonces empezó a usarlo:

irb> hash['a'] << 1 
=> [1] 
irb> hash['b'] << 2 
=> [1, 2] 

pero resulta que:

irb> hash 
=> {} 
+0

¿No está seguro del resultado que está viendo? O lo que el hash realmente contiene? No está claro lo que estás buscando aquí. – jmccarthy

Respuesta

11

intente lo siguiente en su lugar:

hash = Hash.new{|h, k| h[k] = []} 
hash['a'] << 1 # => [1] 
hash['b'] << 2 # => [2] 

La razón que tienes tus resultados inesperados es que ha especificado una matriz vacía como valor predeterminado, pero se usa la misma matriz; no se hace copia La forma correcta es inicializar el valor con una nueva matriz vacía, como en mi código.

+0

+1 "especificó una matriz vacía como valor predeterminado, pero se usa la misma matriz". ¡Bingo! –

+0

¿Qué? Esto es realmente extraño para mí. Cuando usa una cadena, esa cadena no se está reutilizando. La cadena podría ser una especie de tipo de valor, pero pensé que "todo" era un objeto en Ruby. ¿Por qué la diferencia entre cadenas y otros objetos? – Automatico

+0

@ Cort3z: No estoy seguro de lo que quiere decir. Quizás esto puede ayudar a demostrar que no hay diferencia: 'a = b = 'foo'; a.replace 'barra'; b # => 'bar'' –

2

hash['a'] << 1 y hash['b'] << 2 no es sintaxis correcta para crear un par clave/valor. Usted tiene que utilizar = para ello:

hash['a'] = [] 
hash['a'] << 1 

hash['b'] = [] 
hash['b'] << 2 

que debe darle el hash {'a' : [1], 'b' : [2]}

4

El constructor usó las tiendas [] como el valor predeterminado para devolver al acceder a las claves que se desconocen. Dado que Array#<< modifica su receptor en el lugar, esta matriz inicialmente vacía crece.

Para explicar con más detalle:

Al hacer hash['a'] << 1 esto es lo que sucede:

  1. hash mira para ver si hay una clave denominada 'a'
  2. comprueba que no, no hay no hay tal clave.
  3. Parece que ha almacenado un valor predeterminado para devolver.
  4. Dado que lo construyó con Hash.new([]) tiene un valor como [] y lo devuelve.
  5. Ahora se evalúa [] << 1 y esto significa que el hash ahora almacena [1] como el valor que se devuelve cuando se solicita una clave no encontrada previamente.

Si lo que desea es almacenar el par de valores clave en lugar de utilizar la tercera forma del constructor con un bloque:

hash = Hash.new{|h, key| h[key] = []} 
1

Ésta es exactamente el comportamiento que se puede esperar para ver.

Nunca agrega nada al Hash, por lo tanto, el Hash está completamente vacío. Cuando busca una tecla, esa clave nunca existirá, por lo tanto, devuelve el valor predeterminado, que ha especificado que es Array.

Por lo tanto, busca la clave 'a', que no existe, y devuelve el Array que especificó como valor predeterminado. Luego, llama al << en ese Array, que le agrega un valor (1).

A continuación, mirar hacia arriba la tecla 'b', que además no existe, y por lo tanto devuelve el Array ha especificado como el valor por defecto, que ahora contiene el elemento 1 agregó anteriormente. A continuación, llame al << en ese Array, añadiéndole el valor 2.

Usted termina con un Hash que todavía está vacío, ya que nunca le ha agregado nada. El valor predeterminado de Hash ahora es una matriz que contiene los valores 1 y 2.

El resultado que está viendo es porque IRb siempre imprime el resultado de la última expresión que se evaluó. La última expresión en su ejemplo es llamar al << en el Array. << devuelve su receptor, que luego es el valor de retorno de toda la expresión y, por tanto, lo que imprime IRb.

+0

+1 Muy bien dicho. –

+0

¡Hace exactamente lo que usted pregunta, y para nada lo que quiere decir! –

Cuestiones relacionadas