Tutorial :How to refactor this Ruby code aiming to change an hash's symbols into strings?



Question:

I just wrote this piece of code but I'm not quite happy about it.

data = {}  options.each{ |k,v| data.merge!({k.to_s => v}) }  

Basically I have:

{:a => "something", :b => "something else", :c => "blah"}  

... and I want ...

{"a" => "something", "b" => "something else", "c" => "blah"}  

... in order to send it to a gem that do not handle symbols for some reason. In the code I wrote options is the original hash and data is the updated one, but if I could only use 1 variable it'd be even better.

How would you guys refactor my code?


Solution:1

data = Hash[options.map{ |k,v| [k.to_s,v] }]  

For a hash large enough to be interesting, there isn't a significant difference between the answers

require 'benchmark'  options = Hash[('aaaa'..'zzzz').map{|i| [i.to_sym,i]}]  Benchmark.bm(100) do |x|          x.report("map")   {Hash[options.map{ |k,v| [k.to_s,v] }] }          x.report("zip")   {Hash[options.keys.map(&:to_s).zip(options.values)]}          x.report("inject") {options.inject({}) { |h, (k, v)| h[k.to_s] = v; h }}  end                              user     system      total        real  map                   3.490000   0.090000   3.580000 (  4.049015)  zip                   3.780000   0.020000   3.800000 (  3.925876)  inject                3.710000   0.110000   3.820000 (  4.289286)  


Solution:2

Inject seems to win:

require 'benchmark'  a = {:a => "something", :b => "something else", :c => "blah"}  Benchmark.bm(10000) do |x|          x.report("map")   {Hash[a.map{ |k,v| [k.to_s,v] }] }          x.report("zip")   {Hash[a.keys.map(&:to_s).zip(a.values)]}          x.report("inject") {a.inject({}) { |h, (k, v)| h[k.to_s] = v; h }}  end  

gives

user     system      total        real  map      0.000000   0.000000   0.000000 (  0.000033)  zip      0.000000   0.000000   0.000000 (  0.000018)  inject   0.000000   0.000000   0.000000 (  0.000014)  


Solution:3

I'd suggest something like this:

hsh = data.inject({}) { |h, (k, v)| h[k.to_s] = v; h }  

(Taken from a similar SO question)


Solution:4

Rails adds a stringify_keys method to Hash. If you don't use Rails, you can simply copy the code from ActiveSupport (open source ftw!):

def stringify_keys    inject({}) do |options, (key, value)|      options[key.to_s] = value      options    end  end  


Solution:5

With the aid of the activesupport gem, you can make a new hash (or convert an existing one) wherein string and hash keys are interchangeable.

#!/usr/bin/ruby1.8    require 'active_support'    h = HashWithIndifferentAccess.new({'a'=>1, :b=>2})  p h[:a]     => 1  p h['a']    => 1  p h[:b]     => 2  p h['b']    => 2  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »