Ruby: What is the easiest method to update Hash values?

71,266

Solution 1

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.

Solution 2

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

Solution 3

This will do:

h.each {|k, v| h[k] = foo(v)}

Solution 4

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.

Share:
71,266
Misha Moroshko
Author by

Misha Moroshko

I build products that make humans happier. Previously Front End engineer at Facebook. Now, reimagining live experiences at https://muso.live

Updated on July 09, 2022

Comments

  • Misha Moroshko
    Misha Moroshko almost 2 years

    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 ?