ruby hash conditional

Ruby: acceda al hash multidimensional y evite el acceso al objeto nil



conditional (3)

Posible duplicado:
Ruby: Nils en una declaración IF
¿Hay alguna manera clara de evitar llamar a un método en nil en un hash de parámetros anidado?

Digamos que trato de acceder a un hash como este:

my_hash[''key1''][''key2''][''key3'']

Esto es bueno si key1, key2 y key3 existen en el (los) hash (es), pero ¿y si, por ejemplo, key1 no existe?

Entonces obtendría NoMethodError: undefined method [] for nil:NilClass . Y a nadie le gusta eso.

Hasta ahora me ocupo de esto haciendo un condicional como:

if my_hash[''key1''] && my_hash[''key1''][''key2''] ...

¿Es esto apropiado, hay alguna otra forma Rubiest de hacerlo?


Condiciones my_hash[''key1''] && my_hash[''key1''][''key2''] no se siente DRY .

Alternativas:

1) magia de autovivification De esa publicación:

def autovivifying_hash Hash.new {|ht,k| ht[k] = autovivifying_hash} end

Luego, con tu ejemplo:

my_hash = autovivifying_hash my_hash[''key1''][''key2''][''key3'']

Es similar al enfoque Hash.fetch en que ambos operan con nuevos valores hash como valores predeterminados, pero esto mueve los detalles al tiempo de creación. Es cierto que esto es un poco de trampa: nunca volverá a ser ''nil'' solo un hash vacío, que se crea sobre la marcha. Dependiendo de su caso de uso, esto podría ser un desperdicio.

2) Resuma la estructura de datos con su mecanismo de búsqueda y maneje el caso no encontrado detrás de las escenas. Un ejemplo simplista:

def lookup(model, key, *rest) v = model[key] if rest.empty? v else v && lookup(v, *rest) end end ##### lookup(my_hash, ''key1'', ''key2'', ''key3'') => nil or value

3) Si te sientes monádico puedes echarle un vistazo a esto, Maybe


Hay muchos enfoques para esto.

Si usa Ruby 2.3 o superior, puede usar dig

my_hash.dig(''key1'', ''key2'', ''key3'')

Mucha gente se adhiere al rubí simple y encadena las pruebas de && guard.

También podría usar stdlib Hash#fetch :

my_hash.fetch(''key1'', {}).fetch(''key2'', {}).fetch(''key3'', nil)

Algunos prefieren encadenar el método #try de #try .

my_hash.try(:[], ''key1'').try(:[], ''key2'').try(:[], ''key3'')

Otros usan andand

myhash[''key1''].andand[''key2''].andand[''key3'']

Algunas personas piensan que los nilos egocéntricos son una buena idea (aunque alguien podría perseguirte y torturarte si descubrieran que haces esto).

class NilClass def method_missing(*args); nil; end end my_hash[''key1''][''key2''][''key3'']

Podría usar Enumerable#reduce (o alias inject).

[''key1'',''key2'',''key3''].reduce(my_hash) {|m,k| m && m[k] }

O quizás extienda Hash o simplemente su objeto hash de destino con un método de búsqueda anidado

module NestedHashLookup def nest *keys keys.reduce(self) {|m,k| m && m[k] } end end my_hash.extend(NestedHashLookup) my_hash.nest ''key1'', ''key2'', ''key3''

Ah, y ¿cómo podríamos olvidarnos de la mónada maybe ?

Maybe.new(my_hash)[''key1''][''key2''][''key3'']


También podría usar Object#andand .

my_hash[''key1''].andand[''key2''].andand[''key3'']