将哈希转换为嵌套哈希

这个问题与这个问题相反。

给定一个散列,每个键都有一个数组

{ [:a, :b, :c] => 1, [:a, :b, :d] => 2, [:a, :e] => 3, [:f] => 4, } 

将它转换为嵌套哈希的最佳方法是什么?

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

这是一个迭代解决方案,一个递归的解决方案留给读者:

 def convert(h={}) ret = {} h.each do |k,v| node = ret k[0..-2].each {|x| node[x]||={}; node=node[x]} node[k[-1]] = v end ret end convert(your_hash) # => {:f=>4, :a=>{:b=>{:c=>1, :d=>2}, :e=>3}} 

function递归算法:

 require 'facets' class Hash def nestify map_by { |ks, v| [ks.first, [ks.drop(1), v]] }.mash do |key, pairs| [key, pairs.first[0].empty? ? pairs.first[1] : Hash[pairs].nestify] end end end p {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4}.nestify # {:a=>{:b=>{:c=>1, :d=>2}, :e=>3}, :f=>4} 

已经有了一个很好的答案,但我在这个递归解决方案上工作,所以这里是:

 def to_nest(hash) {}.tap do |nest| hash.each_pair do |key, value| nodes = key.dup node = nodes.shift if nodes.empty? nest[node] = value else nest[node] ||= {} nest[node].merge!({nodes => value}) end end nest.each_pair do |key, value| nest[key] = to_nest(value) if value.kind_of?(Hash) end end end 

其他方式:

 def convert(h) h.each_with_object({}) { |(a,n),f| f.update({ a.first=>(a.size==1 ? n : convert({ a[1..-1]=>n })) }) { |_,ov,nv| ov.merge(nv) } } end 

试试吧:

 h = { [:a, :b, :c] => 1, [:a, :b, :d] => 2, [:a, :e] => 3, [:f] => 4, } convert(h) #=> {:a=>{:b=>{:d=>2}, :e=>3}, # :f=>4} 

对于混合散列/数组嵌套结构,您可以使用它。 (也为数组修改)

 def unflatten(h={}) ret = {} h.each do |k,v| node = ret keys = k.split('.').collect { |x| x.to_i.to_s == x ? x.to_i : x } keys.each_cons(2) do |x, next_d| if(next_d.is_a? Fixnum) node[x] ||= [] node=node[x] else node[x] ||={} node=node[x] end end node[keys[-1]] = v end ret end 

如果你使用下面的扁平化。 (用于键而不是数组的单独字符串[如果需要则拆分。)

 def flatten_hash(hash) hash.each_with_object({}) do |(k, v), h| if v.is_a? Hash flatten_hash(v).map do |h_k, h_v| h["#{k}.#{h_k}"] = h_v end elsif v.is_a? Array flatten_array(v).map do |h_k,h_v| h["#{k}.#{h_k}"] = h_v end else h[k] = v end end end def flatten_array(array) array.each_with_object({}).with_index do |(v,h),i| pp v,h,i if v.is_a? Hash flatten_hash(v).map do |h_k, h_v| h["#{i}.#{h_k}"] = h_v end elsif v.is_a? Array flatten_array(v).map do |h_k,h_v| h["#{i}.#{h_k}"] = h_v end end end end 

使用DeepEnumerable :

 require DeepEnumerable h = {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4} h.inject({}){|hash, kv| hash.deep_set(*kv)}