如何使用Ruby哈希表递归地收集深度嵌套的键

4

我希望找到一种聪明的方式来收集深度嵌套键的父键并将它们分配为值。例如...

拿一个哈希表比如...

{
  :foo => {
    :bar => {
      :baz => 'a',
      :bez => 'b',
      :biz => 'c'
    }
  }
}

并从中创建哈希,方法如下...
{
  :foo => {
    :bar => {
      :baz => [:foo, :bar, :baz],
      :bez => [:foo, :bar, :bez],
      :biz => [:foo, :bar, :biz]
    }
  }
}

你尝试过什么吗? - Mark Thomas
1
你到目前为止尝试了什么?你至少应该能够提出一个不那么聪明的方法。 - user229044
3个回答

2

尝试使用递归解决方案:

# array of parent keys initially []
def nested(hash, keys = [])
  # go through each key-value pair
  hash.each do |key, val|
    # if the value is a Hash, recurse and
    # add the key to the array of parents
    if val.is_a? Hash
      nested(val, keys.push(key))
      # remove last parent when we're done
      # with this pair
      keys.pop
    else
      # if the value is not a Hash, set the
      # value to parents + current key
      hash[key] = keys + [key]
    end
  end
end

2
这会改变hash的值,这可能是可以接受的,也可能不可以。 - Cary Swoveland
这很简单,而且兼容Ruby 1.9。我显然想得太多了... - brewster

1
制作一个递归函数。
def recurse(h, acc=[])
  Hash[h.map { |key, value|
    if value.is_a? Hash
      [key, recurse(value, acc + [key])]
    else
      [key, acc + [key]]
    end
  }]
  # You can use h.map {...}.to_h in Ruby 2.1+
end

recurse({
  :foo => {
    :bar => {
      :baz => 'a',
      :bez => 'b',
      :biz => 'c'
    }
  }
})
# =>  {:foo=>
#       {:bar=>
#         {:baz=>[:foo, :bar, :baz],
#                 :bez=>[:foo, :bar, :bez],
#                 :biz=>[:foo, :bar, :biz]}}}

1
我建议使用以下递归方法。

代码

def rehash(h, keys = [])
  h.each_with_object({}) { |(k,v),g|
    g[k] = case v
           when Hash then rehash(v, keys+[k]) 
           else           (keys + [k])       
           end
  }
end

例子

h = { :foo => {
        :bar => {
          :baz => 'a',
          :bez => 'b',
          :biz => 'c'
        }
      }
    }

rehash(h)  
  #=> {:foo=>
        {:bar=>
          {:baz=>[:foo, :bar, :baz],
           :bez=>[:foo, :bar, :bez],
           :biz=>[:foo, :bar, :biz]}}}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接