迭代Ruby中深度嵌套的哈希级别

var*_*tis 29 ruby recursion hash ruby-on-rails ruby-on-rails-3

所以我有一个哈希,对于每个哈希级别,我想存储它的键和值.问题是,值可以是另一个哈希数组.此外,该哈希可以包含键值对,其中值又是另一个哈希数组等等.另外,我不知道每个哈希的嵌套程度有多深.举个例子:

{
  :key1 => 'value1',
  :key2 => 'value2',
  :key3 => {
     :key4 => 'value4',
     :key5 => 'value5'
   },
    :key6 => {
      :key7 => 'value7',
      :key8 => {
        :key9 => 'value9'
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

..等等.我想要做的是保存每个键,值对和其父级的ID.我认为这可能是递归完成的,我只是不确定如何因为我不熟悉递归函数.我知道如何正常迭代数据:

  myHash.each {|key, value|
    ...Do something with the key and value ...
  }
Run Code Online (Sandbox Code Playgroud)

所以我猜测递归调用将是这样的:

def save_pair (myHash)
  myHash.each {|key, value|
    if(value.class != Hash) ? Pair.create(key, value) : save_pair(value)
  }
end
Run Code Online (Sandbox Code Playgroud)

这是未经测试的,我仍然不确定如何合并保存父ID.

Mar*_*ins 21

如果我了解目标,那么您应该能够将父级传递给save方法.对于顶级,它将是零.以下显示了puts用于"保存"的占位符的想法.

def save_pair(parent, myHash)
  myHash.each {|key, value|
    value.is_a?(Hash) ? save_pair(key, value) :
            puts("parent=#{parent.nil? ? 'none':parent}, (#{key}, #{value})")
  }
end
Run Code Online (Sandbox Code Playgroud)

以下是对它的示例调用:

hash = Hash.new
hash["key1"] = "value1"
hash["key2"] = "value2"
hash["key3"] = Hash.new
hash["key3"]["key4"] = "value4"
hash["key3"]["key5"] = "value5"
hash["key6"] = Hash.new
hash["key6"]["key7"] = "value7"
hash["key6"]["key8"] = Hash.new
hash["key6"]["key8"]["key9"] = "value9"

save_pair(nil, hash)
Run Code Online (Sandbox Code Playgroud)


seb*_*ian 10

我知道这是一个迟到的回复,但我只是为你的问题实现了一个非递归的解决方案,并认为值得分享.

class Hash
  def deep_traverse(&block)
    stack = self.map{ |k,v| [ [k], v ] }
    while not stack.empty?
      key, value = stack.pop
      yield(key, value)
      if value.is_a? Hash
        value.each{ |k,v| stack.push [ key.dup << k, v ] }
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,回到原来的问题,您可以:

h = {
  :key1 => 'value1',
  :key2 => 'value2',
  :key3 => {
     :key4 => 'value4',
     :key5 => 'value5'
  },
  :key6 => {
    :key7 => 'value7',
    :key8 => {
      :key9 => 'value9'
    }
  }
}
h.deep_traverse{ |path,value| p [ path, value ] }
# => [[:key6], {:key7=>"value7", :key8=>{:key9=>"value9"}}]
#    [[:key6, :key8], {:key9=>"value9"}]
#    [[:key6, :key8, :key9], "value9"]
#    [[:key6, :key7], "value7"]
#    [[:key3], {:key4=>"value4", :key5=>"value5"}]
#    [[:key3, :key5], "value5"]
#    [[:key3, :key4], "value4"]
#    [[:key2], "value2"]
#    [[:key1], "value1"]
Run Code Online (Sandbox Code Playgroud)

还有一个要点版本.


Mar*_*oda 5

class Hash
  def each_with_parent(parent=nil, &blk)
    each do |k, v|
      Hash === v ? v.each_with_parent(k, &blk) : blk.call([parent, k, v])
    end
  end
end

h = { :a => 1, :b => { :c => 3, :d => 4, :e => { :f => 5 } } }

h.each_with_parent { |i| p i }
# [nil, :a, 1]
# [:b, :c, 3]
# [:b, :d, 4]
# [:e, :f, 5]
Run Code Online (Sandbox Code Playgroud)