Ruby 1.9 regex as a hash key
I am trying this example myhash = {/(\d+)/ => "hello"}
with ruby 1.开发者_开发百科9.2p136 (2010-12-25) [i386-mingw32].
irb(main):004:0> myhash = {/(\d+)/ => "hello"}
=> {/(\d+)/=>"Hello"}
irb(main):005:0> myhash[2222]
=> nil
irb(main):006:0> myhash["2222"]
=> nil
In Rubular which is on ruby1.8.7 the regex works.
What am I missing?Are you looking for this behaviour?
myhash = Hash.new{|h,k| h[k] = 'hello' if k =~ /(\d+)/}
p myhash['aaa'] #=> nil
p myhash #=> {}
p myhash['1234'] #=>" hello"
p myhash #=> {"1234"=>"hello"}
It will not work without some extra code, as it is you are comparing a Regexp object with either an Integer or a String object. They won't be value equal, nor identity equal. They would match but that requires changes to the Hash class code.
irb(main):001:0> /(\d+)/.class
=> Regexp
irb(main):002:0> 2222.class
=> Fixnum
irb(main):003:0> '2222'.class
=> String
irb(main):004:0> /(\d+)/==2222
=> false
irb(main):007:0> /(\d+)/=='2222'
=> false
irb(main):009:0> /(\d+)/.equal?'2222'
=> false
irb(main):010:0> /(\d+)/.equal?2222
=> false
you would have to iterate the hash and use =~ in something like:
hash.each do |k,v|
unless (k=~whatever.to_s).nil?
puts v
end
end
or change the Hash class to try =~ in addition to the normal matching conditions. (I think that last option would be difficult, in mri the Hash class seems to have a lot of C code)
You can put Jean's answer in a default_proc
MAP = {
/1/ => "one",
/2/ => "two",
/\d/ => "number"
}
MAP.default_proc = lambda do |hash, lookup|
hash.each_pair do |key, value|
return value if key =~ lookup
end
return nil
end
p MAP["2"] #=> "two"
p MAP[44] #=> "number"
It never occurred to me to use a regex as a hash key. I'm honestly not sure if that should work, nor exactly how it would work if it should.
In any case, two thoughts:
- In your attempts to lookup the item, you use
hash
, but the hash is namedmyhash
. If I play around with it, I get these results:
hektor ~ ❯❯ irb >> myhash = {/(\d+)/ => "hello"} => {/(\d+)/=>"hello"} >> myhash['2222'] => nil >> myhash[2222] => nil >> myhash[/(\d+)/] => "hello"
This is using Ruby 1.9.2-p180.
Ok, checked and here's what works:
myhash = {/foo/ => "hello"}
myhash[/foo/] # => "hello"
The lookup is on the key, and the key is a regex, not one of the many potential matches of that regex.
There is now a gem called Hashie that provides this feature (and much more): https://github.com/intridea/hashie#rash
It provides a data structure called Rash (short for regex-hash) that can be used like this
myhash = {/(\d+)/ => "hello"}
rash = Hashie::Rash.new(myhash)
>> rash["2222"]
=> "hello"
It really tries to match the key against the regexes so numeric keys won't work unless you convert them to string, which you can do easily by inheriting Rash into your own class
精彩评论