我一直在尝试在 Ruby 中以编程方式制作嵌套的默认哈希,基本上是 Ruby 的简写:
h = Hash.new {|h,k| h[k] = Hash.new}
我想将其扩展到所需的多个级别。我做了以下功能:
def nested_hash(level, default={})
return default if level == 0
return Hash.new{ |h,k| h[k] = nested_hash(level - 1, default) }
end
看起来它工作正常但是我在创建多个 key 时遇到了以下问题
h = nested_hash(1)
h[0][1] = [1, 2, 3] # h is {0=>{1=>[1, 2, 3]}}
h[2] # should give a new Hash, but returns {1=>[1, 2, 3]}
h # {0=>{1=>[1, 2, 3]}, 2=>{1=>[1, 2, 3]}}
为什么函数的默认值变了,变成了之前设置的值?
编辑
我找到了一个有效的解决方案:
def nested_hash(level, default={})
return Hash.new{ |h,k| h[k] = default } if level <= 1
Hash.new{ |h,k| h[k] = nested_hash(level - 1, default) }
end
没关系,这不会以类似的方式工作:
h = nested_hash(1)
h[0][1] = [1, 2, 3]
h[2][0] # nil
h # {0=>{1=>[1, 2, 3]}, 2=>{1=>[1, 2, 3]}}
我仍然对为什么在 key 之间共享原始默认值感到困惑。
最佳答案
出于好奇:
hash =
Hash.new do |h, k|
h[k] = h.dup.clear.extend(Module.new do
define_method(:level, ->{ h.level - 1 })
end).tap { |this| raise "🔥" if this.level <= 0 }
end.extend(Module.new { define_method(:level, ->{ 5 }) })
#⇒ {}
hash["0"]["1"]["2"]["3"]
#⇒ {}
hash["0"]["1"]["2"]["3"]["4"]
#⇒ RuntimeError: "🔥"
或者,作为一个函数:
def nhash lvl
Hash.new do |h, k|
h[k] = h.dup.clear.extend(Module.new do
define_method(:level, ->{ h.level - 1 })
end).tap { |this| raise "🔥" if this.level < 0 }
end.extend(Module.new { define_method(:level, ->{ lvl }) })
end
导致:
✎ h = nhash 2
#⇒ {}
✎ h[0][1] = [1, 2, 3]
#⇒ [1, 2, 3]
✎ h[2][0]
#⇒ {}
✎ h[2][0][5]
#⇒ RuntimeError: 🔥
如有必要,可能会重置默认过程而不是提高。
这种方法的唯一缺点是,在尝试调用高于允许的级别时,将创建所有中间空哈希。 也可以通过定义方法、累积路径(而不是简单地返回级别)和在提升之前删除空 parent 来克服。
关于ruby-on-rails - 在 Ruby 中通过递归嵌套哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54558485/