Changing every value in a hash in Ruby

I want to change every value in a hash so as to add '%' before and after the value so

{ :a=>'a' , :b=>'b' }

must be changed to

{ :a=>'%a%' , :b=>'%b%' }

What's the best way to do this?


Solution 1:

In Ruby 2.1 and higher you can do

{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h

Solution 2:

If you want the actual strings themselves to mutate in place (possibly and desirably affecting other references to the same string objects):

# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }

If you want the hash to change in place, but you don't want to affect the strings (you want it to get new strings):

# 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 }

If you want a new hash:

# 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}%"] } ]

Solution 3:

Ruby 2.4 introduced the method Hash#transform_values!, which you could use.

{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"} 

Solution 4:

The best way to modify a Hash's values in place is

hash.update(hash){ |_,v| "%#{v}%" }

Less code and clear intent. Also faster because no new objects are allocated beyond the values that must be changed.