June 14, 2017
This blog is part of our Ruby 2.4 series.
It is a common use case to transform the values of a hash.
{ a: 1, b: 2, c: 3 } => { a: 2, b: 4, c: 6 }
{ a: "B", c: "D", e: "F" } => { a: "b", c: "d", e: "f" }
We can transform the values of a hash destructively (i.e. modify the original hash with new values) or non-destructively (i.e. return a new hash instead of modifying the original hash).
Prior to Ruby 2.4, we need to use following code to transform the values of a hash.
# Ruby 2.3 Non-destructive version
> hash = { a: 1, b: 2, c: 3 }
#=> {:a=>1, :b=>2, :c=>3}
> hash.inject({}) { |h, (k, v)| h[k] = v * 2; h }
#=> {:a=>2, :b=>4, :c=>6}
> hash
#=> {:a=>1, :b=>2, :c=>3}
> hash = { a: "B", c: "D", e: "F" }
#=> {:a=>"B", :c=>"D", :e=>"F"}
> hash.inject({}) { |h, (k, v)| h[k] = v.downcase; h }
#=> {:a=>"b", :c=>"d", :e=>"f"}
> hash
#=> {:a=>"B", :c=>"D", :e=>"F"}
# Ruby 2.3 Destructive version
> hash = { a: 1, b: 2, c: 3 }
#=> {:a=>1, :b=>2, :c=>3}
> hash.each { |k, v| hash[k] = v * 2 }
#=> {:a=>2, :b=>4, :c=>6}
> hash
#=> {:a=>2, :b=>4, :c=>6}
> hash = { a: "B", c: "D", e: "F" }
#=> {:a=>"B", :c=>"D", :e=>"F"}
> hash.each { |k, v| hash[k] = v.downcase }
#=> {:a=>"b", :c=>"d", :e=>"f"}
> hash
#=> {:a=>"b", :c=>"d", :e=>"f"}
Active Support has already implemented handy methods Hash#transform_values and Hash#transform_values! to transform hash values.
Now, Ruby 2.4 has also implemented Hash#map_v and Hash#map_v! and then renamed to Hash#transform_values and Hash#transform_values! for the same purpose.
# Ruby 2.4 Non-destructive version
> hash = { a: 1, b: 2, c: 3 }
#=> {:a=>1, :b=>2, :c=>3}
> hash.transform_values { |v| v * 2 }
#=> {:a=>2, :b=>4, :c=>6}
> hash
#=> {:a=>1, :b=>2, :c=>3}
> hash = { a: "B", c: "D", e: "F" }
#=> {:a=>"B", :c=>"D", :e=>"F"}
> hash.transform_values(&:downcase)
#=> {:a=>"b", :c=>"d", :e=>"f"}
> hash
#=> {:a=>"B", :c=>"D", :e=>"F"}
# Ruby 2.4 Destructive version
> hash = { a: 1, b: 2, c: 3 }
#=> {:a=>1, :b=>2, :c=>3}
> hash.transform_values! { |v| v * 2 }
#=> {:a=>2, :b=>4, :c=>6}
> hash
#=> {:a=>2, :b=>4, :c=>6}
> hash = { a: "B", c: "D", e: "F" }
#=> {:a=>"B", :c=>"D", :e=>"F"}
> hash.transform_values!(&:downcase)
#=> {:a=>"b", :c=>"d", :e=>"f"}
> hash
#=> {:a=>"b", :c=>"d", :e=>"f"}
If this blog was helpful, check out our full blog archive.