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
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.
Ok, I guess there is the issue of changing something you are iterating
over, but according to this thread:
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.
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