2008-10-04 13 views
34

Crear hashes de hashes en Ruby permite realizar dos (o más) búsquedas dimensionales convenientes. Sin embargo, al insertar uno siempre se debe verificar si el primer índice ya existe en el hash. Por ejemplo:Hashes of Hashes Idiom en Ruby?

h = Hash.new 
h['x'] = Hash.new if not h.key?('x') 
h['x']['y'] = value_to_insert 

Sería preferible hacer lo siguiente, donde el nuevo hash se crea automáticamente:

h = Hash.new 
h['x']['y'] = value_to_insert 

Del mismo modo, cuando se busca un valor en el que no existe ya el primer índice, sería preferible si se devuelve nil en lugar de recibir un método indefinido para el error '[]'.

looked_up_value = h['w']['z'] 

Se podría crear una clase contenedora hash que tiene este comportamiento, pero ¿hay una ya existente un lenguaje de Ruby para llevar a cabo esta tarea?

+0

¿Hay un hash de modismos hash que devolverían 0 después de cierta profundidad? (Estoy contando cosas y estoy usando h [: foo] [: bar] [: baz] + = 1) –

Respuesta

54

se puede pasar a la función Hash.new un bloque que se ejecuta para producir un valor por defecto en caso de que no existe el valor buscado aún:

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

Por supuesto, esto se puede hacer de forma recursiva.

/EDIT: Wow, hay an article respondiendo a esta pregunta.

En aras de la exhaustividad, aquí está la solución del artículo para los hashes de profundidad arbitraria:

hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)})) 

Los créditos van a Kent de Data Noise.

+1

Wow. Eso es impresionante. –

+0

Enlace muerto. Impresionante solución sin embargo. –

+1

El enlace inactivo se cambia aquí http://inquirylabs.com/blog2009/2006/09/20/ruby-hashes-of-arbitrary-depth/ – Autodidact

4

Autovivificación, como se llama, es a la vez una bendición y una maldición. El problema puede ser que si "miras" un valor antes de que se defina, estás atascado con este hash vacío en la ranura y tendrías que podarlo más tarde.

Si no te importa un poco de anarquía, siempre puede atascarse en o iguales declaraciones de estilo que permitirán a construir la estructura esperada como se consulta es:

((h ||= { })['w'] ||= { })['z']