Basically I want to assign an array using #dig
.
My has has to be like this:
hash = {
:first => {
:second => [1,2,3,4]
}
}
and I would use Hash#dig
hash.dig(:first, :second) = [1,2,3,4]
How can I assign this value?
Basically I want to assign an array using #dig
.
My has has to be like this:
hash = {
:first => {
:second => [1,2,3,4]
}
}
and I would use Hash#dig
hash.dig(:first, :second) = [1,2,3,4]
How can I assign this value?
You can create a hash that behaves like what you want. Hash.new
takes a block which is invoked whenever a key lookup fails. We can create an empty hash when that happens:
hash = Hash.new { |hash, key| hash[key] = Hash.new(&hash.default_proc) }
hash[:first][:second] = [1, 2, 3, 4]
hash # => {:first=>{:second=>[1, 2, 3, 4]}}
Note though that merely accessing an inexistent key will result in the creation of a new hash:
hash.dig(:a, :b, :c) # => {}
hash # => {:first=>{:second=>[1, 2, 3, 4]}, :a=>{:b=>{:c=>{}}}}
hash[:foo].nil? # => false
dig cannot be used to assign a value to a Hash, this method has been built only for accessing a value.
For your case, you can do one of both things :
hash = { first: { second: [1, 2, 3, 4] } }
Or :
hash[:first] = { second: [1, 2, 3, 4] }
You can also use the approach in that post : How to set dynamically value of nested key in Ruby hash
They create a new hash method to dynamically assign nested values to a Hash.
I've assumed that the answer to the question I raised in a comment on the question is "yes".
One could use Enumerable#reduce (a.k.a. inject
):
def undig(*keys, value)
keys[0..-2].reverse_each.reduce (keys.last=>value) { |h,key| { key=>h } }
end
undig(:first, :second, [1,2,3,4])
#=> {:first=>{:second=>[1, 2, 3, 4]}}
or recursion:
def undig(*keys, value)
keys.empty? ? value : { keys.first=>undig(*keys.drop(1), value) }
end
undig(:first, :second, [1,2,3,4])
#=> {:first=>{:second=>[1, 2, 3, 4]}}