Ответ 1
Самый простой способ - построить ваш хэш с помощью блока:
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 = Hash.new({ })
так как для всех записей по умолчанию будет использоваться хэш точно такой же.
Кроме того, как отмечает Фрогз, вы можете сделать auto-vivived хэши самовоспроизводятся с помощью 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
.