0

I have a hash

  hash = {"some_wierd_name"=>"cheesemonster", .....}

and I want this hash as

  hash = {"preferred_name"=>"cheesemonster", ......}

What is the shortest way to do that?

2
  • 1
    Hashes are ordered, do you need to preserve that order? Commented Jul 1, 2016 at 16:55
  • 2
    @mu makes a good point. Maybe you want { "preferred_name" => hash.delete("some_weird_name") }.merge hash. Commented Jul 1, 2016 at 16:59

4 Answers 4

6
hash["preferred_name"] = hash.delete("some_wierd_name")

Hash keys are frozen strings, they can’t be modified inplace, and the frozen state can’t be removed from an object. That said, tricks with prepend and replace won’t work resulting in:

RuntimeError: can't modify frozen String

Therefore, there is the only possibility: to remove the old value and insert the new one.

Sign up to request clarification or add additional context in comments.

1 Comment

If packaged in a method, hash is needed as the last line.
3
hash = {"some_wierd_name"=>"cheesemonster"}

hash["preferred_name"] = hash["some_wierd_name"]
hash.delete("some_wierd_name")

1 Comment

Just a note that (since hash.delete("some_wierd_name") => "cheesemonster") if this is packaged in a method, hash is needed as the last line.
1
  • If we are looking to replace the key/value both, can be done easily by using rails except method. You can also use the delete method but one key/value pair at a time but be using except can remove 2 or more key/value pair.

    hash = {a: 1, b:2, c: 3}
    hash.except!(:a)[:d] = 4 
    and it is similar to these two following line
    hash.except!(:a) 
    hash[:d] = 4
    hash = {:b=>2, :c=>3, :d=>4}
    
  • Changing only key of the hash, value remains same. One can also use the reject. reject and delete_if are same.

    hash[:e] = hash.delete(:d) 
         or 
    temp = hash[d]
    hash.delete_if{|key| key ==:d }
    hash[:e] = temp
    hash = {:b=>2, :c=>3, :e=>4}
    
  • Changing only value, the key remains same. This one pretty easy.

    hash[:e] = 5
    

References :

Comments

0

for a single key, use delete

hash["preferred_name"] = hash.delete("some_wierd_name")

If you need to update all the keys, i suggest using inject

new_hash = hash.inject({}) do |returned_hash, (key, value)|
  returned_hash[key] = value.upcase;
  returned_hash
end

12 Comments

Self-answers are not a problem and are not frowned upon in general. Also, the answer is correct and pretty complete, nothing to worry about.
As a tiny addition, instead of inject, you can also use each_with_object to get rid of the second line in the block.
@HolgerJust, I would agree with you if it were a challenging question, but this one is not. I have seen this technique for renaming a key many, many times on SO.
Why value.upcase? And why not use each_with_object({}) when you're not really injecting? Or use h.merge(k => v.upcase) as the block if you are injecting. And your inject version isn't renaming any keys, it is modifying the values.
@Sean, I think "shameless point-grab" is rather harsh. Some very experienced Rubiests here regularly post questions and then immediately post an answer. In effect, they are saying, "This the best I could come up with. Is there a better way?" Typically it is a challenging problem they've encountered on the job. It has nothing to do with rep.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.