Я хочу изменить каждое значение в хэше, чтобы добавить '%' до и после значения, чтобы
{ :a=>'a' , :b=>'b' }
необходимо изменить на
{ :a=>'%a%' , :b=>'%b%' }
Какой лучший способ сделать это?
Я хочу изменить каждое значение в хэше, чтобы добавить '%' до и после значения, чтобы
{ :a=>'a' , :b=>'b' }
необходимо изменить на
{ :a=>'%a%' , :b=>'%b%' }
Какой лучший способ сделать это?
Если вы хотите, чтобы фактические строки сами мутировали на месте (возможно, и желательно влиять на другие ссылки на одни и те же строковые объекты):
# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }
Если вы хотите, чтобы хэш изменился на месте, но вы не хотите влиять на строки (вы хотите, чтобы они получили новые строки):
# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |key,str| my_hash[key] = "%#{str}%" }
my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }
Если вы хотите новый хеш:
# Ruby 1.8.6+
new_hash = Hash[*my_hash.map{|k,str| [k,"%#{str}%"] }.flatten]
# Ruby 1.8.7+
new_hash = Hash[my_hash.map{|k,str| [k,"%#{str}%"] } ]
В Ruby 2.1 и выше вы можете сделать
{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
Лучший способ изменить значения хеширования -
hash.update(hash){ |_,v| "%#{v}%" }
Меньше кода и четкое намерение. Также быстрее, потому что новые объекты не выделяются за пределы значений, которые необходимо изменить.
Немного более читаемый, map
он для массива одноэлементных хэшей и reduce
, который с merge
the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
Ruby 2.4 представил метод Hash#transform_values!
, который вы могли бы использовать.
{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"}
Один метод, который не вводит побочные эффекты в оригинал:
h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]
Hash # map также может быть интересным для чтения, так как объясняет, почему Hash.map
не возвращает хеш (именно поэтому результирующий массив пар [key,value]
преобразуется в новый хэш) и предоставляет альтернативные подходы к одному и тому же общему шаблону.
Счастливое кодирование.
[Отказ от ответственности: я не уверен, что семантика Hash.map
изменяется в Ruby 2.x]
Для этой задачи существует новый метод "Rails way":) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values
my_hash.each do |key, value|
my_hash[key] = "%#{value}%"
end
Hash.merge! является самым чистым решением
o = { a: 'a', b: 'b' }
o.merge!(o) { |key, value| "%#{ value }%" }
puts o.inspect
> { :a => "%a%", :b => "%b%" }
После тестирования с помощью RSpec:
describe Hash do
describe :map_values do
it 'should map the values' do
expect({:a => 2, :b => 3}.map_values { |x| x ** 2 }).to eq({:a => 4, :b => 9})
end
end
end
Вы можете реализовать Hash # map_values следующим образом:
class Hash
def map_values
Hash[map { |k, v| [k, yield(v)] }]
end
end
Затем эту функцию можно использовать следующим образом:
{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}