2017-10-06 2 views
0

C'est un peu confus.Comment vérifier si le membre de hachage ruby ​​existe récursivement?

Si vous avez un hachage qui contient plus de hachages qui ont également des hachages et ainsi de suite, comment déterminez-vous si un membre a plus d'un niveau de profondeur?

Par exemple:

hash 1 = 
{ 
    "layer1" => 
    { 
     "layer2" => 
     { 
      "layer3" => ['Something', 'Array'] 
     } 
    } 
} 

Comment iriez-vous sur la vérification « quelque chose » existe dans le hachage ci-dessus si le hachage ne dispose que:

hash2 = 
{ 
    "layer1" => 
    { 
     "layer2" => ['Other Array'] 
    } 
} 

Par exemple, je voudrais essayer de faire:

if hash2['layer1']['layer2']['layer3'].contains? 'Something' 
    puts "Found Something!" 
end 

Mais cela erreur méthode non définie `contient? ' pour néant: NilClass. Où layer3 serait la NilClass parce qu'elle n'existe pas. Il suffirait que l'un de ces hashses incorporés soit nul alors disons qu'il n'existe pas, mais vous ne pouvez pas facilement tester leur existence car cela retournera aussi Nil si vous êtes un calque trop profond. Y at-il une fonction dans ruby ​​qui vérifie chaque couche de niveau supérieur pour Nil récursivement au lieu du membre spécifique que vous demandez lorsque vous appelez .nil? E.g. Ce que je penserais fonctionnerait!

if hash2['layer1']['layer2']['layer3'].nil? 
    puts 'layer3 exists' 
end 

Mais .nil? seulement vérifie si 'layer3' existe. Y at-il une méthode qui commence à 'layer1' puis vérifie si 'layer2' existe, puis 'layer3' et ainsi de suite. Et à l'une des parties sont nuls, il renvoie faux? Parce que si 'layer2' ou 'layer1' n'existait pas, il commettrait une erreur en disant une méthode non définie `[] 'pour nil: NilClass.

+0

https://stackoverflow.com/q/8301566/5101493 peut aider –

Répondre

1

Découvrez Hash#dig(). Il prend un tableau de clés et les recherche récursivement, renvoyant nil si l'un d'eux est manquant. A partir de la documentation:

h = { foo: {bar: {baz: 1}}} 

h.dig(:foo, :bar, :baz)   #=> 1 
h.dig(:foo, :zot)     #=> nil 

note juste que si baz était nil, que le premier appel aurait retourné nil. Donc, c'est seulement un remplacement pour vérifier si une clé imbriquée existe si vous savez que vous n'aurez pas nil s stockés dans votre hachage.

+1

'.dig' est génial! Gardez également à l'esprit que cela ne fonctionne que dans les versions 2.3+. Si cela se passe à l'intérieur d'une gemme ou d'une autre bibliothèque, cela ne fonctionnera pas pour les utilisateurs dans les versions précédentes. – whodini9

+0

Omg, c'est exactement ce que je cherchais. Il est difficile de trouver une solution à ce problème car la manière de formuler ce problème peut conduire à de nombreuses versions différentes. – jStaff

0

pas la meilleure solution, mais je l'ai écrit ceci:

h = {"layer1"=> 
     {"layer2"=> 
      {"layer3"=>["Something", "Array"]} 
     }, 
    "layerx" => ["d"], 
    "layerz" => {"layera" => "deep"} 
} 

def vals(h) 
    return h if !h.is_a?(Hash) 
    h.values.map(&method(:vals)).flatten 
end 
vals(h) #=> ["Something", "Array", "d", "deep"] 

vals donne les valeurs imbriquées au fond de hachage-es. Vous pouvez vérifier si votre élément est là.