Is there any way simpler than
if hash.key?('a')
hash['a']['b'] = 'c'
else
hash['a'] = {}
hash['a']['b'] = 'c'
end
Is there any way simpler than
if hash.key?('a')
hash['a']['b'] = 'c'
else
hash['a'] = {}
hash['a']['b'] = 'c'
end
The easiest way is to construct your Hash with a block argument:
hash = Hash.new { |h, k| h[k] = { } }
hash['a']['b'] = 1
hash['a']['c'] = 1
hash['b']['c'] = 1
puts hash.inspect
# "{"a"=>{"b"=>1, "c"=>1}, "b"=>{"c"=>1}}"
This form for new
creates a new empty Hash as the default value. You don't want this:
hash = Hash.new({ })
as that will use the exact same hash for all default entries.
Also, as Phrogz notes, you can make the auto-vivified hashes auto-vivify using default_proc
:
hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
UPDATE: I think I should clarify my warning against Hash.new({ })
. When you say this:
h = Hash.new({ })
That's pretty much like saying this:
h = Hash.new
h.default = { }
And then, when you access h
to assign something as h[:k][:m] = y
, it behaves as though you did this:
if(h.has_key?(:k))
h[:k][:m] = y
else
h.default[:m] = y
end
And then, if you h[:k2][:n] = z
, you'll end up assigning h.default[:n] = z
. Note that h
still says that h.has_key?(:k)
is false.
However, when you say this:
h = Hash.new(0)
Everything will work out okay because you will never modified h[k]
in place here, you'll only read a value from h
(which will use the default if necessary) or assign a new value to h
.
a simple one, but hash should be a valid hash object
(hash["a"] ||= {})['b'] = "c"
If you create hash
as the following, with default value of a new (identically default-valued) hash: (thanks to Phrogz for the correction; I had the syntax wrong)
hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
Then you can do
hash["a"]["b"] = "c"
without any additional code.
The question here:
Is auto-initialization of multi-dimensional hash array possible in Ruby, as it is in PHP?
provides a very useful AutoHash
implementation that does this.
class NilClass
def [](other)
nil
end
end
Once you defined that, everything will work automatically. But be aware that from now on nil
would behave as an empty hash when used as a hash.