Given:
h = {foo: {bar: 1}}
How to set bar if you don't know how many keys you have?
For example: keys = [:foo, :bar]
h[keys[0]][keys[1]] = :ok
But what if keys can be of arbitrary length and h is of arbitrary depth?
If you're using Ruby 2.3+ then you can use dig thusly:
h.dig(*keys[0..-2])[keys.last] = :ok
dig follows a path through the hash and returns what it finds. But dig won't copy what it finds so you get the same reference that is in h. keys[0..-2] grabs all but the last element of keys so h.dig(*keys[0..-2]) gives you the {bar: 1} Hash from inside h, then you can modify it in-place with a simple assignment.
You could also say:
*head, tail = keys
h.dig(*head)[tail] = :ok
if that's clearer to you than [0..-2].
If you don't have dig then you can do things like:
*head, tail = keys
head.inject(h) { |m, k| m[k] }[tail] = :ok
Of course, if you're not certain that the path specified by keys exists then you'll need to throw in a some nil checks and decide how you should handle keys that don't specify a path into h.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With