How to use fetch method for nested hash?

I have the following hash:

hash = {'name' => { 'Mike' => { 'age' => 10, 'gender' => 'm' } } } 

I can access age by:

 hash['name']['Mike']['age'] 

What if I used the Hash#fetch method? How can I get the key from a nested hash?

As Sergio said, the way to do this (without creating something for yourself) would be through the fetch method chain:

 hash.fetch('name').fetch('Mike').fetch('age') 
+10
source share
6 answers

There is no built-in method that I know of. I have it in my current project

 class Hash def fetch_path(*parts) parts.reduce(self) do |memo, key| memo[key.to_s] if memo end end end # usage hash.fetch_path('name', 'Mike', 'age') 

You can easily change it to use #fetch instead of #[] (if you want).

+2
source

Starting with Ruby 2.3.0, you can use Hash#dig :

 hash.dig('name', 'Mike', 'age') 

It also comes with an added bonus that if some values ​​in the path are nil , you will get nil instead of an exception.

You can use the ruby_dig gem until you migrate.

+29
source

If your goal is to raise a KeyError when there is no intermediate key, you need to write your own method. If instead you use fetching to provide default values ​​for missing keys, you can get around using fetching by building hashes with default values.

 hash = Hash.new { |h1, k1| h1[k1] = Hash.new { |h2, k2| h2[k2] = Hash.new { |h3, k3| } } } hash['name']['Mike'] # {} hash['name']['Steve']['age'] = 20 hash # {"name"=>{"Mike"=>{}, "Steve"=>{"age"=>20}}} 

This will not work for randomly nested hashes, you need to choose the maximum depth when creating them.

0
source

Like Ruby 2.3.0:

You can also use &. , called the "safe navigation operator", like: hash&.[]('name')&.[]('Mike')&.[]('age') . It is absolutely safe.

Using dig unsafe because hash.dig(:name, :Mike, :age) will fail if hash is zero.

However, you can combine these two as: hash&.dig(:name, :Mike, :age) .

Thus, any of the following methods is safe to use:

hash&.[]('name')&.[]('Mike')&.[]('age')

hash&.dig(:name, :Mike, :age)

0
source

A version that uses the method instead of adding to the Hash class for others using Ruby 2.2 or lower.

 def dig(dict, *args) key = args.shift if args.empty? return dict[key] else dig(dict[key], *args) end end 

And so you can do:

 data = { a: 1, b: {c: 2}} dig(data, :a) == 1 dig(data, :b, :c) == 2 
0
source

if you can

using:

 hash[["ayy","bee"]] 

instead:

 hash["ayy"]["bee"] 

it will save a lot of trouble

-3
source

Source: https://habr.com/ru/post/955018/


All Articles