So I have a nested hash like below:
nested_hash = {
foo: foo,
bar: {
foo: foo,
bar: {
foo: foo,
bar: {
foo: bar
}
}
}
}
To access the values at different levels, you could use multiple methods, like so:
def one_level(key1)
nested_hash[key1]
end
def two_levels(key1, key2)
nested_hash[key1][key2]
end
def three_levels(key1, key2, key3)
nested_hash[key1][key2][key3]
end
But maybe you need it in one single method like this:
def up_to_three_levels(key1, key2, key3)
if key1 && key2 && key3
nested_hash[key1][key2][key3]
elif key1 && key2
nested_hash[key1][key2]
else
nested_hash[key1]
end
end
This is obviously not ideal and doesn't scale. It would be nice if I could just pass an array of arbitrary length to reach an arbitrary level. Is there a method that does that?
(For context: The problem I'm trying to solve is that I need to take a key path as a parameter and use it to fetch data from multiple different data structures.)
Yes. It's called dig
:
nested_hash.dig(key1, key2, key3)
It doesn't take an array, but there is the splat operator (*
) that lets you convert an array to a list of parameters, like so:
nested_hash.dig(*[key1, key2, key3])
Not that you would have to implement this yourself, but I think it's useful to know that it's a very simple recursive problem that can be solved with only a few lines of code:
def dig(collection, keys)
if keys.length == 0 || collection == nil
collection
else
dig(collection[keys[0]], keys.drop(1))
end
end
Also worth noting is that dig
also exists on arrays and that you can have a mix of arrays and hash maps in your nested structure and seamlessly traverse it with dig
.