Подтвердить что ты не робот

Инициализация хэшей

Я часто пишу что-то вроде этого:

a_hash['x'] ? a_hash['x'] += ' some more text' : a_hash['x'] = 'first text'

Там должен быть лучший способ сделать это, но я не могу его найти.

4b9b3361

Ответ 1

Существует два способа создания начальных значений для Hash.

Один - передать один объект в Hash.new. Это хорошо работает во многих ситуациях, особенно если объект является замороженным значением, но если объект имеет внутреннее состояние, это может иметь неожиданные побочные эффекты. Поскольку один и тот же объект разделяется между всеми ключами без назначенного значения, изменение внутреннего состояния для одного будет отображаться во всех.

a_hash = Hash.new "initial value"
a_hash['a'] #=> "initial value"
# op= methods don't modify internal state (usually), since they assign a new
# value for the key.
a_hash['b'] += ' owned by b' #=> "initial value owned by b"
# other methods, like #<< and #gsub modify the state of the string
a_hash['c'].gsub!(/initial/, "c's")
a_hash['d'] << " modified by d"
a_hash['e'] #=> "c value modified by d"

Другой метод инициализации - передать Hash.new блок, который вызывается каждый раз, когда запрашивается значение для ключа, который не имеет значения. Это позволяет использовать отдельное значение для каждого ключа.

another_hash = Hash.new { "new initial value" }
another_hash['a'] #=> "new initial value" 
# op= methods still work as expected
another_hash['b'] += ' owned by b'
# however, if you don't assign the modified value, it lost,
# since the hash rechecks the block every time an unassigned key value is asked for
another_hash['c'] << " owned by c" #=> "new initial value owned by c"
another_hash['c'] #=> "new initial value"

Блок передается двумя аргументами: хэш запрашивается для значения и используется ключ. Это дает вам возможность назначить значение для этого ключа, так что один и тот же объект будет отображаться каждый раз, когда указывается конкретный ключ.

yet_another_hash = Hash.new { |hash, key| hash[key] = "#{key} initial value" }
yet_another_hash['a'] #=> "a initial value"
yet_another_hash['b'] #=> "b initial value"
yet_another_hash['c'].gsub!('initial', 'awesome')
yet_another_hash['c'] #=> "c awesome value"
yet_another_hash #=> { "a" => "a initial value", "b" => "b initial value", "c" => "c awesome value" }

Этот последний метод является тем, который я чаще всего использую. Это также полезно для кэширования результата дорогого расчета.

Ответ 2

Вы можете указать начальное значение при создании хэша:

a_hash = { 'x' => 'first text' }
// ...
a_hash['x'] << ' some more text'

Ответ 3

Конструктор Hash в своем первом аргументе имеет значение по умолчанию для ключей. Таким образом

>> a_hash = Hash.new "first text"
=> {}
>> a_hash['a']
=> "first text"
>> a_hash['b'] += ", edit"
=> "first text, edit"

Ответ 4

Поскольку вы используете хеш для сбора строк, я предполагаю, что вы просто хотите убедиться, что вы не получите ошибку при добавлении. Поэтому я бы сделал хэш по умолчанию пустой. Затем вы можете добавлять без ошибок, независимо от хеш-ключа.

a_hash = Hash.new {|h,k| h[k]=""}

texts = ['first text', ' some more text']

texts.each do |text|
  a_hash['x'] << text
end

puts a_hash['x'] #=> 'first text some more text'

Ответ 5

Если вы не хотите вмешиваться в значение default= (существующий хэш), вы можете сократить свой код, используя fetch(key [, default]) в качестве поиска со значением по умолчанию:

a_hash['x'] = a_hash.fetch('x', 'first_text') + ' some more text'