Что такое Ruby-эквивалент Python defaultdict?
В Python я могу создать хэш, где каждый элемент имеет значение по умолчанию, когда оно сначала ссылается (также известно как "автовивитация" ). Вот пример:
from collections import defaultdict
d = defaultdict(int)
d["new_key"] += 1
print d
Печать dict указывает, что значение для "new_key" равно 1.
Какой эквивалент в Ruby? Этот код вызывает ошибку:
d = {}
d[:new_key] += 1
puts d
test.rb:3:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Ответы
Ответ 1
Для этого вы можете использовать первый аргумент метода Hash.new
:
d = Hash.new 0
d[:new_key] += 1
d[:new_key] #=> 1
d[:foo] #=> 0
Будьте осторожны - вы можете случайно изменить значение по умолчанию:
h = Hash.new("Go Fish")
h[:unknown_key] #=> "Go Fish"
h[:unknown_key].upcase! #=> "GO FISH"
h[:next_key] #=> "GO FISH"
Как указано в его ответе "mu is too short", лучше использовать proc, например:
h = Hash.new { |h, k| h[k] = 0 }
Ответ 2
Вы можете назначить значение по default=
используя default=
:
d.default = 0
Обратите внимание, что это на самом деле не будет автоматически авививизировать, но просто заставит d[:new_key]
возвращать ноль без фактического добавления ключа :new_key
. default=
также может вызвать проблемы, если вы собираетесь изменить значение по умолчанию; это означает, что d.default = [ ]
почти всегда является ошибкой, поскольку массив не будет скопирован при доступе по умолчанию.
Лучший выбор обычно default_proc=
:
d.default_proc = proc { |h, k| h[k] = 0 }
Это позволяет вам иметь различные значения по умолчанию и позволяет добавлять новый ключ (или не в зависимости от того, как proc
процесс).
Вы также можете установить их при создании хэша:
d = Hash.new(0)
d = Hash.new { |h, k| h[k] = 0 }
Ответ 3
Стандартный метод new
для Hash принимает блок. Этот блок вызывается в случае попытки доступа к ключу в Хэше, который не существует. Блок передается сам Хэш и запрошенный ключ (два параметра) и должен возвращать значение, которое должно быть возвращено для запрошенного ключа.
Это может быть использовано для создания автогенерируемого хеша, среди прочего:
h = Hash.new{ |h,k| h[k] = 'default value'}