How to change Hash values?
Solution 1
my_hash.each { |k, v| my_hash[k] = v.upcase }
or, if you'd prefer to do it non-destructively, and return a new hash instead of modifying my_hash
:
a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h }
This last version has the added benefit that you could transform the keys too.
Solution 2
Since ruby 2.4.0
you can use native Hash#transform_values
method:
hash = {"a" => "b", "c" => "d"}
new_hash = hash.transform_values(&:upcase)
# => {"a" => "B", "c" => "D"}
There is also destructive Hash#transform_values!
version.
Solution 3
You can collect the values, and convert it from Array to Hash again.
Like this:
config = Hash[ config.collect {|k,v| [k, v.upcase] } ]
Solution 4
This will do it:
my_hash.each_with_object({}) { |(key, value), hash| hash[key] = value.upcase }
As opposed to inject
the advantage is that you are in no need to return the hash again inside the block.
Solution 5
There's a method for that in ActiveSupport v4.2.0. It's called transform_values
and basically just executes a block for each key-value-pair.
Since they're doing it with a each
I think there's no better way than to loop through.
hash = {sample: 'gach'}
result = {}
hash.each do |key, value|
result[key] = do_stuff(value)
end
Update:
Since Ruby 2.4.0 you can natively use #transform_values
and #transform_values!
.
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on October 17, 2020Comments
-
Admin over 3 years
I'd like to replace each
value
in a hash withvalue.some_method
.For example, for given a simple hash:
{"a" => "b", "c" => "d"}`
every value should be
.upcase
d, so it looks like:{"a" => "B", "c" => "D"}
I tried
#collect
and#map
but always just get arrays back. Is there an elegant way to do this?UPDATE
Damn, I forgot: The hash is in an instance variable which should not be changed. I need a new hash with the changed values, but would prefer not to define that variable explicitly and then loop over the hash filling it. Something like:
new_hash = hash.magic{ ... }
-
kch about 15 yearsthat's good, but it should be noted that it only works for when j has a destructive method that acts unto itself. So it can't handle the general value.some_method case.
-
Chris Doggett about 15 yearsGood point, and with his update, your second solution (non-destructive) is the best.
-
Marcus over 12 yearsThe first suggestion is not appropriate; modifying an enumerable element while iterating leads to undefined behavior - this is valid in other languages also. Here's a reply from Matz (he replies to an example using an Array, but the answer is generic): j.mp/tPOh2U
-
Kelvin over 12 years@Marcus I agree that in general such modification should be avoided. But in this case it's probably safe, because the modification doesn't change future iterations. Now if another key (that wasn't the one passed to the block) was assigned, then there would be trouble.
-
Kelvin over 12 years@Adam @kch
each_with_object
is a more convenient version ofinject
when you don't want to end the block with the hash:my_hash.each_with_object({}) {|(k, v), h| h[k] = v.upcase }
-
rewritten about 10 yearsThere is also a very neat syntax to convert a list of pairs into a hash, so you can write
a_new_hash = Hash[ my_hash.map { |k, v| [k, v.upcase] } ]
-
roman-roman almost 10 yearswith Ruby 2 you can write
.to_h
-
Christian Di Lorenzo almost 9 yearsI like that this method does not modify the original hash.
-
ioquatix almost 8 yearsIs this efficient?
-
rj487 almost 7 yearsgreat, it also comes with rails 4.2.1 apidock.com/rails/v4.2.1/Hash/transform_values
-
David Hempy about 5 yearsSee @potashin 's answer below for a better, modern solution.