What Is the Most Ruby-Ish Way of Accessing Nested Hash Values at Arbitrary Depths

What is the most ruby-ish way of accessing nested hash values at arbitrary depths?

def val_for(hash, keys)
keys.reduce(hash) { |h, key| h[key] }
end

This will raise an exception if some intermediate key is not found. Note also that this is completely equivalent to keys.reduce(hash, :[]), but this may very well confuse some readers, I'd use the block.

ruby use array tvalues to index nested hash of hash

And then there's:

keys.inject(hash, :fetch)

or for earlier Ruby versions:

keys.inject(hash) {|h, k| h[k]}

If you did want to use recursion, a more Rubyesque approach would be:

def get_value(obj, keys)
keys.empty? ? obj : get_value(obj[keys[0]], keys[1..-1])
end

Access nested hash element specified by an array of keys

hash = { "a" => { "b" => 'foo' }}
array = ["a", "b"]

array.inject(hash,:fetch)
# => "foo"
array.inject(hash,:[])
# => "foo"

How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?

Ruby 2.3.0 introduced a new method called dig on both Hash and Array that solves this problem entirely.

name = params.dig(:company, :owner, :name)

It returns nil if the key is missing at any level.

If you are using a version of Ruby older than 2.3, you can use the ruby_dig gem or implement it yourself:

module RubyDig
def dig(key, *rest)
if value = (self[key] rescue nil)
if rest.empty?
value
elsif value.respond_to?(:dig)
value.dig(*rest)
end
end
end
end

if RUBY_VERSION < '2.3'
Array.send(:include, RubyDig)
Hash.send(:include, RubyDig)
end


Related Topics



Leave a reply



Submit