这些天我通常的做法是:
h = Hash.new { |h,k| h[k] = {} }
这将为您提供一个散列,该散列创建一个新的散列作为缺少的密钥的条目,但为第二级密钥返回nil:
h['foo'] -> {}
h['foo']['bar'] -> nil
您可以将其嵌套以添加多个层,这些层可以通过以下方式寻址:
h = Hash.new { |h, k| h[k] = Hash.new { |hh, kk| hh[kk] = {} } }
h['bar'] -> {}
h['tar']['zar'] -> {}
h['scar']['far']['mar'] -> nil
您还可以使用default_proc
方法无限期链接:
h = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
h['bar'] -> {}
h['tar']['star']['par'] -> {}
上面的代码创建了一个散列,其默认进程使用相同的默认进程创建了一个新的散列.因此,当查找不可见的密钥时,作为默认值创建的哈希将具有相同的默认行为.
EDIT: More details
Ruby哈希允许您控制在查找新键时如何创建默认值.如果指定,此行为将封装为Proc
对象,并可通过default_proc
和default_proc=
方法访问.也可以通过向Hash.new
传递一个块来指定默认进程.
让我们把这个代码分解一下.这不是惯用的ruby,但更容易将其分成多行:
1. recursive_hash = Hash.new do |h, k|
2. h[k] = Hash.new(&h.default_proc)
3. end
第1行将变量recursive_hash
声明为新的Hash
,并将块开始为recursive_hash
的default_proc
.块被传递给两个对象:h
,这是正在执行密钥查找的Hash
实例,k
,这是正在查找的密钥.
第2行将哈希中的默认值设置为新的Hash
实例.该散列的默认行为是通过传递一个Proc
来提供的,该Proc
是根据正在查找的散列的default_proc
创建的;即,块本身定义的默认过程.
以下是IRB会议的一个例子:
irb(main):011:0> recursive_hash = Hash.new do |h,k|
irb(main):012:1* h[k] = Hash.new(&h.default_proc)
irb(main):013:1> end
=> {}
irb(main):014:0> recursive_hash[:foo]
=> {}
irb(main):015:0> recursive_hash
=> {:foo=>{}}
创建recursive_hash[:foo]
处的散列时,其default_proc
由recursive_hash
的default_proc
提供.这有两个影响:
recursive_hash[:foo]
的默认行为与recursive_hash
相同.
recursive_hash[:foo]
的default_proc
创建的哈希的默认行为与recursive_hash
相同.
因此,继续IRB,我们得到以下结果:
irb(main):016:0> recursive_hash[:foo][:bar]
=> {}
irb(main):017:0> recursive_hash
=> {:foo=>{:bar=>{}}}
irb(main):018:0> recursive_hash[:foo][:bar][:zap]
=> {}
irb(main):019:0> recursive_hash
=> {:foo=>{:bar=>{:zap=>{}}}}