Самый простой способ - создать свой хэш с аргументом блока:
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}}"
Эта форма для new
создает новый пустой хэш в качестве значения по умолчанию. Вы не хотите этого:
hash = Hash.new({ })
, поскольку это будет использовать точно такой же хэш для всех записей по умолчанию.
Кроме того, как отмечает Фрогз, вы можете автоматически оживлять хэши, используя default_proc
:
hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
ОБНОВЛЕНИЕ : Я думаю, что я должен уточнить свое предупреждение против Hash.new({ })
. Когда вы говорите это:
h = Hash.new({ })
Это очень похоже на следующее:
h = Hash.new
h.default = { }
И затем, когда вы получаете доступ к h
, чтобы назначить что-то как h[:k][:m] = y
, он ведет себя так, как будто вы сделали это:
if(h.has_key?(:k))
h[:k][:m] = y
else
h.default[:m] = y
end
И затем, если вы h[:k2][:n] = z
, вы в конечном итоге назначите h.default[:n] = z
. Обратите внимание, что h
все еще говорит, что h.has_key?(:k)
является ложным.
Однако, когда вы говорите это:
h = Hash.new(0)
Все будет хорошо, потому что здесь вы никогда не измените h[k]
, вы только прочитаете значение из h
(при необходимости будет использоваться значение по умолчанию) или назначите новое значение для h
.