开发者

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].

It doesn't work as expected (edit: as it turned out it shouldn't work as I was expecting):

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:

  1. In your attempts to lookup the item, you use hash, but the hash is named myhash.
  2. 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜