Как назначить хеш ['a'] ['b'] = 'c', если хеш ['a'] не существует? - PullRequest
20 голосов
/ 04 мая 2011

Есть ли способ проще, чем

if hash.key?('a')
  hash['a']['b'] = 'c' 
else  
  hash['a'] = {}
  hash['a']['b'] = 'c' 
end

Ответы [ 5 ]

39 голосов
/ 04 мая 2011

Самый простой способ - создать свой хэш с аргументом блока:

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.

10 голосов
/ 04 мая 2011

простой, но хеш должен быть допустимым хеш-объектом

(hash["a"] ||= {})['b'] = "c"
2 голосов
/ 04 мая 2011

Если вы создадите hash следующим образом со значением по умолчанию нового (идентично значению по умолчанию) хэша: (спасибо Phrogz за исправление; у меня неправильный синтаксис)

hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }

Тогда вы можете сделать

hash["a"]["b"] = "c"

без дополнительного кода.

0 голосов
/ 14 мая 2016
class NilClass
  def [](other)
    nil
  end
end

Как только вы это определили, все будет работать автоматически. Но имейте в виду, что теперь nil будет вести себя как пустой хеш при использовании в качестве хеша.

0 голосов
/ 24 ноября 2014

Вопрос здесь: Возможна ли автоматическая инициализация многомерного хеш-массива в Ruby, как в PHP? обеспечивает очень полезную реализацию AutoHash, которая делает это.

...