Reputation: 171489
Say:
h = { 1 => 10, 2 => 20, 5 => 70, 8 => 90, 4 => 34 }
I would like to change each value v
to foo(v
), such that h
will be:
h = { 1 => foo(10), 2 => foo(20), 5 => foo(70), 8 => foo(90), 4 => foo(34) }
What is the most elegant way to achieve this ?
Upvotes: 55
Views: 86136
Reputation: 2107
Rails (and Ruby 2.4+ natively) have Hash#transform_values
, so you can now do {a:1, b:2, c:3}.transform_values{|v| foo(v)}
https://ruby-doc.org/core-2.4.0/Hash.html#method-i-transform_values
If you need it to work in nested hashes as well, Rails now has deep_transform_values
(source):
hash = { person: { name: 'Rob', age: '28' } }
hash.deep_transform_values{ |value| value.to_s.upcase }
# => {person: {name: "ROB", age: "28"}}
Upvotes: 27
Reputation: 3391
You can use update
(alias of merge!
) to update each value using a block:
hash.update(hash) { |key, value| value * 2 }
Note that we're effectively merging hash
with itself. This is needed because Ruby will call the block to resolve the merge for any keys that collide, setting the value with the return value of the block.
Upvotes: 119
Reputation: 81671
The following is slightly faster than @Dan Cheail's for large hashes, and is slightly more functional-programming style:
new_hash = Hash[old_hash.map {|key, value| key, foo(value)}]
Hash#map
creates an array of key value pairs, and Hash.[]
converts the array of pairs into a hash.
Upvotes: 6
Reputation: 9605
There's a couple of ways to do it; the most straight-forward way would be to use Hash#each
to update a new hash:
new_hash = {}
old_hash.each do |key, value|
new_hash[key] = foo(value)
end
Upvotes: 0