2012-07-21 52 views
10

Probé el siguiente código ruby, que pensé que devolvería un hash de longitud de palabra a las palabras con esas longitudes. En cambio, está vacío.ruby ​​sumando hash con valor de matriz

map = Hash.new(Array.new)  
strings = ["abc","def","four","five"] 
strings.each do |word| 
    map[word.length] << word 
end 

Sin embargo, si modifico a

map = Hash.new 
strings = ["abc","def","four","five"] 
strings.each do |word| 
    map[word.length] ||= [] 
    map[word.length] << word 
end 

No funciona.

¿La primera versión no solo crea un hash cuyos valores predeterminados son una matriz vacía? En este caso, no entiendo por qué los 2 bloques dan valores diferentes.

+0

Esto es extraño. Para el primer ejemplo, funciona si haces 'map = Hash.new {| h, k | h [k] = []} ' –

Respuesta

21

El problema es que en realidad no está asignando nada a las teclas de acceso directo, solo está utilizando el operador << para modificar el contenido existente de un valor predeterminado. Como no asigna nada a la tecla hash, no se agrega. De hecho, se dará cuenta el valor por defecto es el modificado:

h = Hash.new [] 
p h[0]   # [] 
h[0] << "Hello" 
p h    # {} 
p h[0]   # ["Hello"] 
p h[1]   # ["Hello"] 

Esto se debe a la misma Array objeto se mantiene como el valor predeterminado. Se puede solucionar mediante el operador +, aunque puede ser menos eficiente:

map = Hash.new [] 
strings = ["abc", "def", "four", "five"] 

strings.each do |word| 
    map[word.length] += [word] 
end 

Y ahora funciona como se esperaba.

+0

me ayudó mucho, gracias! Esto no funcionó para mí, sin embargo, hasta que cambié la 'palabra' después de' + = 'para que fuera una matriz, como' [palabra] ' – Subtletree

2

Creo que lo que realmente significa la primera versión es que el valor predeterminado es solo una matriz. El segundo ejemplo crea explícitamente una nueva matriz si todavía no existe una.

Esto parece una buena lectura para más información clarify.

+0

Ah, ya veo. Eso tiene sentido. –

11

En cualquier caso, se debe utilizar Enumerable#group_by:

["abc", "def", "four", "five"].group_by(&:length) 
#=> {3=>["abc", "def"], 4=>["four", "five"]} 
+0

Gracias. Todavía estoy aprendiendo ruby, así que aprender los modismos es útil. –

+0

Brillante, gracias! – Johnsyweb

Cuestiones relacionadas