Как изменить значения хеширования?
Я хотел бы заменить каждый value
на хэш с value.some_method
.
Например, для заданного простого хэша:
{"a" => "b", "c" => "d"}`
каждое значение должно быть .upcase
d, поэтому оно выглядит так:
{"a" => "B", "c" => "D"}
Я пробовал #collect
и #map
, но всегда просто возвращаю массивы. Есть ли элегантный способ сделать это?
ОБНОВЛЕНИЕ
Черт, я забыл: хэш находится в переменной экземпляра, которая не должна быть изменена. Мне нужен новый хэш с измененными значениями, но я бы предпочел не указывать эту переменную явно, а затем перебирать хэш, заполняя ее. Что-то вроде:
new_hash = hash.magic{ ... }
Ответы
Ответ 1
my_hash.each { |k, v| my_hash[k] = v.upcase }
или, если вы предпочитаете делать это без разрушения и возвращать новый хэш вместо изменения my_hash
:
a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h }
Эта последняя версия имеет дополнительное преимущество, которое также можно было бы изменить.
Ответ 2
Вы можете собирать значения и преобразовывать их из Array в Hash снова.
Вот так:
config = Hash[ config.collect {|k,v| [k, v.upcase] } ]
Ответ 3
Это будет сделано:
my_hash.each_with_object({}) { |(key, value), hash| hash[key] = value.upcase }
В отличие от inject
преимущество состоит в том, что вам не нужно возвращать хэш снова внутри блока.
Ответ 4
Так как ruby 2.4.0
вы можете использовать собственный метод Hash#transform_values
:
hash = {"a" => "b", "c" => "d"}
new_hash = hash.transform_values(&:upcase)
# => {"a" => "B", "c" => "D"}
Существует также деструктивная Hash#transform_values!
версия.
Ответ 5
Попробуйте эту функцию:
h = {"a" => "b", "c" => "d"}
h.each{|i,j| j.upcase!} # now contains {"a" => "B", "c" => "D"}.
Ответ 6
Там есть метод для ActiveSupport v4.2.0. Он назывался transform_values
и в основном просто выполняет блок для каждой пары ключ-значение.
Так как они делают это с each
, я думаю, что нет лучшего способа, чем прокрутить.
hash = {sample: 'gach'}
result = {}
hash.each do |key, value|
result[key] = do_stuff(value)
end
Ответ 7
Я делаю что-то вроде этого:
new_hash = Hash [* original_hash.collect {| ключ, значение | [ключ, значение + 1]}. flatten]
Это предоставляет вам возможности для преобразования ключа или значения с помощью любого выражения (и это, безразлично, конечно).
Ответ 8
Вы можете пойти еще дальше и сделать это на вложенном хэше. Разумеется, это справедливо для проектов Rails.
Здесь некоторый код для обеспечения хэша params находится в UTF-8:
def convert_hash hash
hash.inject({}) do |h,(k,v)|
if v.kind_of? String
h[k] = to_utf8(v)
else
h[k] = convert_hash(v)
end
h
end
end
# Iconv UTF-8 helper
# Converts strings into valid UTF-8
#
# @param [String] untrusted_string the string to convert to UTF-8
# @return [String] your string in UTF-8
def to_utf8 untrusted_string=""
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
ic.iconv(untrusted_string + ' ')[0..-2]
end
Ответ 9
Ruby имеет метод tap
(1.8.7, 1.9.3 и 2.1.0), что очень полезно для таких вещей.
original_hash = { :a => 'a', :b => 'b' }
original_hash.clone.tap{ |h| h.each{ |k,v| h[k] = v.upcase } }
# => {:a=>"A", :b=>"B"}
original_hash # => {:a=>"a", :b=>"b"}
Ответ 10
new_hash = old_hash.merge(old_hash) do |_key, value, _value|
value.upcase
end
# old_hash = {"a" => "b", "c" => "d"}
# new_hash = {"a" => "B", "c" => "D"}
Ответ 11
Если вы знаете, что значения являются строками, вы можете вызвать метод replace на них во время цикла: таким образом вы будете измените значение.
Altohugh это ограничивается случаем, когда значения являются строками и, следовательно, не полностью отвечает на вопрос, я думал, что это может быть полезно кому-то.
Ответ 12
Rails конкретных
Если кому-то нужно только вызвать метод to_s
для каждого из значений и не использует Rails 4.2 (который включает в себя метод transform_values
ссылка), вы можете сделать следующее:
original_hash = { :a => 'a', :b => BigDecimal('23.4') }
#=> {:a=>"a", :b=>#<BigDecimal:5c03a00,'0.234E2',18(18)>}
JSON(original_hash.to_json)
#=> {"a"=>"a", "b"=>"23.4"}
Примечание. Необходимо использовать библиотеку "json".
Примечание 2: Это также превратит ключи в строки