Best way to replace hash keys

What is the most optimal and neatest way to replace keys in a hash given
a particular condition?

I’m currently using delete_if and putting replacement values into a new
hash before merging them back into the original hash. Another approach
would to simply rebuild a whole new hash.

Contrived example: given searchReplacePairs hash of { search =>

replace } pairs,

convert any String keys to a Regexp.

newPairs = { }
searchReplacePairs.delete_if do |search, replace|
if search.class == String
newPairs[Regexp.new(search)] = replace
end
end
searchReplacePairs.merge! newPairs

Many thanks,
Alex

What is the point of doing the merge? You can change the hash directly:

stuff = {
Regexp.new(‘hello’) => ‘goodbye’,
Regexp.new(‘world’) => ‘venus’,
‘world’ => ‘mars’,

}

stuff.delete_if do |key, val|
if key.class == String
stuff[Regexp.new(key)] = val
true #**
end
end

p stuff

–output:–
{/hello/=>“goodbye”, /world/=>“mars”}

**If the key is a String and you change it to a Regexp, and then you set
the value to nil, the block will evaluate to false, which means the
String key will not be deleted–that’s why I added a true at the end of
the if.

You should also consider whether you need to do a Regexp.escape() on the
string before converting it to a regex.

7stud – wrote in post #1003039:

What is the point of doing the merge?

Ok, I guess there is the issue of changing something you are iterating
over, but according to this thread:

http://www.rhinocerus.net/forum/lang-ruby/433787-iterating-changing-hash-under-1-9-1-a.html

delete_if safely sequesters away the original key/value pairs for
iteration. But as others point out, it may not be the best idea to rely
on that behavior, or make others who read your code wonder about that
issue.

On Jun 3, 10:27am, Alex A. [email protected]
wrote:

end
end
searchReplacePairs.merge! newPairs

I’m not sure your example actually works, I think you’ll end up with
both string AND regexp keys.

Here’s an alternative:

require ‘facets/hash/rekey’

searchReplacePairs.rekey! do |search, replace|
search.class == String ? Regexp.new(search) : search
end

See
http://rubydoc.info/github/rubyworks/facets/master/Hash#rekey-instance_method

It’s one of my favorite core extensions.

On Jun 4, 8:35am, Intransition [email protected] wrote:

I’m not sure your example actually works, I think you’ll end up with
both string AND regexp keys.

Here’s an alternative:

require ‘facets/hash/rekey’

searchReplacePairs.rekey! do |search, replace|
search.class == String ? Regexp.new(search) : search
end

Slight correction:

searchReplacePairs.rekey! do |search|
search.class == String ? Regexp.new(search) : search
end

Which gives me an idea about a possible improvement to the method :wink:

On Fri, Jun 3, 2011 at 10:27 AM, Alex A.
[email protected] wrote:

What is the most optimal and neatest way to replace keys in a hash given a
particular condition?

I wrote an article about this back in 2009:
http://avdi.org/devblog/2009/11/20/hash-transforms-in-ruby/

Hope it’s helpful.

Thanks to everyone for the responses.

I’ll probably work with rekey because of the clean syntax, very
readable. Plus that extension generally looks very useful.

Thanks for the link Avdi, I’ve been struggling with using inject so this
gives great insight.

I am picking apart Harry’s example but I find it hard to read and I
wonder if the array conversion, transposing, zipping, and flattening
would be inefficient. Always interested in seeing alternative uses
though :slight_smile:

Best wishes,
Alex

On Fri, Jun 3, 2011 at 11:27 PM, Alex A.
[email protected] wrote:

end
end
searchReplacePairs.merge! newPairs

Many thanks,
Alex

I won’t claim this is the best way but it may be worth a look.
Is it doing what you want or did I misunderstand?

a = {“ONE”=>“1”,2=>“2”,“THREE”=>“3”}

t = a.to_a.transpose
b = Hash[*(t[0].map{|x| x.class==String ? Regexp.new(x)
:x}.zip(t[1])).flatten]
p b #> {/ONE/=>“1”, 2=>“2”, /THREE/=>“3”}

Harry

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs