How to assign hash['a']['b']= 'c' if hash['a'] doesn't exist?

后端 未结 5 1150
渐次进展
渐次进展 2020-11-29 04:46

Is there any way simpler than

if hash.key?(\'a\')
  hash[\'a\'][\'b\'] = \'c\' 
else  
  hash[\'a\'] = {}
  hash[\'a\'][\'b\'] = \'c\' 
end
相关标签:
5条回答
  • 2020-11-29 05:09
    class NilClass
      def [](other)
        nil
      end
    end
    

    Once you defined that, everything will work automatically. But be aware that from now on nil would behave as an empty hash when used as a hash.

    0 讨论(0)
  • 2020-11-29 05:11

    a simple one, but hash should be a valid hash object

    (hash["a"] ||= {})['b'] = "c"
    
    0 讨论(0)
  • 2020-11-29 05:19

    The question here: Is auto-initialization of multi-dimensional hash array possible in Ruby, as it is in PHP? provides a very useful AutoHash implementation that does this.

    0 讨论(0)
  • 2020-11-29 05:21

    The easiest way is to construct your Hash with a block argument:

    hash = Hash.new { |h, k| h[k] = { } }
    hash['a']['b'] = 1
    hash['a']['c'] = 1
    hash['b']['c'] = 1
    puts hash.inspect
    # "{"a"=>{"b"=>1, "c"=>1}, "b"=>{"c"=>1}}"
    

    This form for new creates a new empty Hash as the default value. You don't want this:

    hash = Hash.new({ })
    

    as that will use the exact same hash for all default entries.

    Also, as Phrogz notes, you can make the auto-vivified hashes auto-vivify using default_proc:

    hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
    

    UPDATE: I think I should clarify my warning against Hash.new({ }). When you say this:

    h = Hash.new({ })
    

    That's pretty much like saying this:

    h = Hash.new
    h.default = { }
    

    And then, when you access h to assign something as h[:k][:m] = y, it behaves as though you did this:

    if(h.has_key?(:k))
        h[:k][:m] = y
    else
        h.default[:m] = y
    end
    

    And then, if you h[:k2][:n] = z, you'll end up assigning h.default[:n] = z. Note that h still says that h.has_key?(:k) is false.

    However, when you say this:

    h = Hash.new(0)
    

    Everything will work out okay because you will never modified h[k] in place here, you'll only read a value from h (which will use the default if necessary) or assign a new value to h.

    0 讨论(0)
  • 2020-11-29 05:23

    If you create hash as the following, with default value of a new (identically default-valued) hash: (thanks to Phrogz for the correction; I had the syntax wrong)

    hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
    

    Then you can do

    hash["a"]["b"] = "c"
    

    without any additional code.

    0 讨论(0)
提交回复
热议问题