Ruby 1.9 regex as a hash key

前端 未结 5 1144
南笙
南笙 2021-02-13 13:39

I am trying this example myhash = {/(\\d+)/ => \"hello\"} with ruby 1.9.2p136 (2010-12-25) [i386-mingw32].
It doesn\'t work as exp

相关标签:
5条回答
  • 2021-02-13 14:05

    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)

    0 讨论(0)
  • 2021-02-13 14:17

    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"}
    
    0 讨论(0)
  • 2021-02-13 14:21

    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 讨论(0)
  • 2021-02-13 14:24

    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.

    0 讨论(0)
  • 2021-02-13 14:27

    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"
    
    0 讨论(0)
提交回复
热议问题