2

How do I rename all the keys in a Ruby hash, based on their original key name, for example, adding a prefix to all of them?

hash = { foo: "bar", test: "blah", hello: "world" }

# do something to `hash`
=> { pre_foo: "bar", pre_test: "blah", pre_hello: "world" }

Would I do this with Hash#map or something similar?


I got something working with help from "How to change all the keys of a hash by a new set of given keys?" modifying it to access the current key with:

Hash[hash.map {|k, v| ["pre_#{k}".to_sym, v] }]

Is there a better way?

Community
  • 1
  • 1
mswieboda
  • 1,026
  • 2
  • 10
  • 30

4 Answers4

2

You can do this too:

hash = { foo: "bar", test: "blah", hello: "world" }
def add_prefix(hsh, key)
  hsh.each_with_object({}) do |(k,v),h|
     h["#{key}#{k}".to_sym] = v
  end
end

add_prefix(hash, 'pre_')
# => {:pre_foo=>"bar", :pre_test=>"blah", :pre_hello=>"world"}
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
  • 1
    Hello, Arup. Two suggestions: define as a `Hash` method, as OP wants `hash.add_prefix...` and get rid of all that ugly stuff from pry. – Cary Swoveland Sep 08 '14 at 20:17
  • I edited it as a one-liner, instead of using a function, seems cleaner: `hash.each_with_object({}) {|(k,v),h| h["pre_#{k}".to_sym] = v }` – mswieboda Sep 08 '14 at 20:22
  • @CarySwoveland I have *edited*. But _monkey patching_ is not a good idea and not all people like it too.. So.. I didn't :-) – Arup Rakshit Sep 09 '14 at 03:18
  • Arup, I agree with you entirely, and see that the OP isn't interested in monkey-patching here. – Cary Swoveland Sep 09 '14 at 03:42
  • `h["#{key}k".to_sym]` won't return the results you show. It's a good idea to copy/paste the working code and its results. – the Tin Man Sep 09 '14 at 15:53
2
hash.map {|k, v| ["pre_#{k}".to_sym, v] }.to_h

This idea seems the best I think. But make sure that the version of your Ruby supports to_h.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
user3476791
  • 1,072
  • 1
  • 9
  • 14
  • I was going to accept the answer I edited, but had to wait a day, this is the approach I went with, it's the cleanest, nice one liner – mswieboda Sep 09 '14 at 20:52
1

Modified from "How to change all the keys of a hash by a new set of given keys?"

hash.map {|k, v| ["pre_#{k}".to_sym, v] }.to_h

Maybe there is a better way to do this. It seems a little like overkill to convert to an array, then back to a hash.

Community
  • 1
  • 1
mswieboda
  • 1,026
  • 2
  • 10
  • 30
  • It depends on your version of Ruby. `to_h` was added to Array, which converts an array of name/value pairs to a hash. `hash.map{ |k, v| ["pre_#{k}".to_sym, v] }.to_h # => {:pre_foo=>"bar", :pre_test=>"blah", :pre_hello=>"world"}`. `map` is going to convert it to an array of name/values, so the conversion back is necessary. – the Tin Man Sep 08 '14 at 20:08
  • I'm thinking of using this since it's shorter, more readable, and after benchmarking it (10000 keys in hash), seems almost twice as fast, although not much of a huge deal – mswieboda Sep 08 '14 at 20:44
1

If you want to "rename" the keys in place, rather than create a new hash, it's easiest to simultaneously add a new key and delete an existing one (keys cannot be renamed directly):

def add_prefix(hash, prefix)
  hash.keys.each { |k| hash[(prefix+k.to_s).to_sym] = hash.delete(k) }
end

hash = { foo: "bar", test: "blah", hello: "world" }

add_prefix(hash, "pre_")
  #=> {:pre_foo=>"bar", :pre_test=>"blah", :pre_hello=>"world"}
hash
  #=> {:pre_foo=>"bar", :pre_test=>"blah", :pre_hello=>"world"}
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • you're right I did have `add_prefix` in there, I meant that more as pseudo code. I'd rather not monkey patch Hash, thanks for the answer though! – mswieboda Sep 08 '14 at 20:34
  • It's not necessary to show "edit". We can see changes if it's important. If you're concerned about showing the revision history, a simple `---` in the text will give you a horizontal bar which nicely delineates things. – the Tin Man Sep 09 '14 at 15:55
  • Sucker, I edited as per your comment. @theTinMan, thanks for the suggestion. – Cary Swoveland Sep 09 '14 at 16:01