Ruby 将哈希转换为嵌套哈希
这个问题与之相反 给定一个散列,每个键都有一个数组,如Ruby 将哈希转换为嵌套哈希,ruby,hash,nested,Ruby,Hash,Nested,这个问题与之相反 给定一个散列,每个键都有一个数组,如 { [:a, :b, :c] => 1, [:a, :b, :d] => 2, [:a, :e] => 3, [:f] => 4, } 将其转换为嵌套哈希的最佳方法是什么 { :a => { :b => {:c => 1, :d => 2}, :e => 3, }, :f => 4, } 这是一
{
[: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}}
已经有了一个很好的答案,但我研究了这个递归解决方案,所以它是:
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
函数递归算法:
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 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}
对于混合散列/数组嵌套结构,您可以使用此选项。(对阵列也进行了修改) 如果您使用下面的工具进行展平。(键的点分隔字符串,而不是数组[split on.if you need]) 使用:
没有什么是“递归的”,这是简单的嵌套的。特定的散列可能不是递归的,但不管使用什么算法,它都是递归的。但我认为你说的有道理。我编辑过。到目前为止你都试了些什么?您尝试的解决方案不起作用的具体原因是什么?谢谢。你的答案比递归地做要好得多。这很好。为什么默认为空哈希?注意:通过更改为
h.each_with_object({})do|(k,v),ret |
可以删除第一行和最后一行(尽管我不确定回答问题时是否each_with_object
(v1.9+)可用)。当然,您也可以使用reduce
。
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
require DeepEnumerable
h = {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4}
h.inject({}){|hash, kv| hash.deep_set(*kv)}