Ruby on rails 将散列深度转换为路径的平面数组
我想获得一些技巧和示例,说明如何转换如下不同的结构:Ruby on rails 将散列深度转换为路径的平面数组,ruby-on-rails,ruby,Ruby On Rails,Ruby,我想获得一些技巧和示例,说明如何转换如下不同的结构: h = { friend: [:id, :name], meta: { board: [:id, :name], column: [:id, :name, users: [:id, :name]] }, trello: [:id, :name] } [[:friend, :id], [:friend, :name], [:meta, :board, :id], [:met
h = {
friend: [:id, :name],
meta: {
board: [:id, :name],
column: [:id, :name, users: [:id, :name]]
},
trello: [:id, :name]
}
[[:friend, :id],
[:friend, :name],
[:meta, :board, :id],
[:meta, :board, :name],
[:meta, :column, :id],
[:meta, :column, :name],
[:meta, :column, :users, :id],
[:meta, :column, :users, :name],
[:trello, :id],
[:trello, :name]]
如下所示进入阵列:
h = {
friend: [:id, :name],
meta: {
board: [:id, :name],
column: [:id, :name, users: [:id, :name]]
},
trello: [:id, :name]
}
[[:friend, :id],
[:friend, :name],
[:meta, :board, :id],
[:meta, :board, :name],
[:meta, :column, :id],
[:meta, :column, :name],
[:meta, :column, :users, :id],
[:meta, :column, :users, :name],
[:trello, :id],
[:trello, :name]]
此数组的每个元素都是完整路径。这是非常标准的。您可以通过递归使用:
# for Array.wrap; It's needed in pure ruby script, not in Rails
require 'active_support/all'
def deep_flatten(tree, path, result)
tree.each do |key, value|
Array.wrap(value).each do |e|
if e.is_a? Hash
deep_flatten(e, path + [key], result)
else
result << path + [key, e]
end
end
end
end
tree = {
friend: [:id, :name],
meta: {
board: [:id, :name],
column: [:id, :name, users: [:id, :name]]
},
trello: [:id, :name]
}
result = []
deep_flatten(tree, [], result)
result.each do |line|
puts line.inspect
end
代码
解释
递归方法执行的操作总是很难解释。根据我的经验,最好的方法是在代码中添加puts语句。然而,这本身是不够的,因为在查看输出时,很难跟踪递归级别,在该级别上获得特定结果,方法何时调用自身,以及返回到哪个版本的自身。解决方法是缩进和取消缩进结果,这就是我在下面所做的
INDENT = 4
@col = -INDENT
def indent
@col += INDENT
end
def undent
@col -= INDENT
end
def pu(s)
print " "*@col
puts s
end
导致显示以下内容
passed obj = {:friend=>[:id, :name], :meta=>{:board=>[:id, :name],
:column=>[:id, :name, {:users=>[:id, :name]}]}, :trello=>[:id, :name]}
processing hash...
k=friend, v=[:id, :name], a=[]
passed obj = [:id, :name]
processing array...
v = id
a = []
v is a symbol
v = name
a = [:id]
v is a symbol
returning [:id, :name]
你尝试了什么?请澄清或删除最后一句话,并进行编辑。请注意,我将您的哈希值设置为变量h的值。这样,用户都可以在答案和评论中引用相同的变量,而无需定义它。很酷,非常感谢,这是一个了不起的解决方案!我刚刚删除了对Array.wrap的依赖关系,我完全明白了这个想法。@Renat添加了一些链接。
def doit(obj)
begin # rem
indent # rem
pu "passed obj = #{obj}" # rem
case obj
when Hash
pu "processing hash..." # rem
obj.each_with_object([]) do |(k,v),a|
pu "k=#{k}, v=#{v}, a=#{a}"
case v
when Symbol
a << v
else
doit(v).each { |aa| a << [k, *aa] }
end
end
else
pu "processing array..." # rem
obj.each_with_object([]) do |v,a|
pu "v = #{v}" # rem
pu "a = #{a}" # rem
case v
when Symbol
pu "v is a symbol" # rem
a << v
else
pu "calling doit(v). v is a hash or an array" # rem
doit(v).each { |aa| a << aa }
end
end
end.
tap { |o| pu "returning #{o}" } # rem
ensure # rem
undent # rem
end
end
doit(h)
passed obj = {:friend=>[:id, :name], :meta=>{:board=>[:id, :name],
:column=>[:id, :name, {:users=>[:id, :name]}]}, :trello=>[:id, :name]}
processing hash...
k=friend, v=[:id, :name], a=[]
passed obj = [:id, :name]
processing array...
v = id
a = []
v is a symbol
v = name
a = [:id]
v is a symbol
returning [:id, :name]
k=meta, v={:board=>[:id, :name], :column=>[:id, :name, {:users=>[:id, :name]}]},
a=[[:friend, :id], [:friend, :name]]
passed obj = {:board=>[:id, :name],
:column=>[:id, :name, {:users=>[:id, :name]}]}
processing hash...
k=board, v=[:id, :name], a=[]
passed obj = [:id, :name]
processing array...
v = id
a = []
v is a symbol
v = name
a = [:id]
v is a symbol
returning [:id, :name]
k=column, v=[:id, :name, {:users=>[:id, :name]}],
a=[[:board, :id], [:board, :name]]
passed obj = [:id, :name, {:users=>[:id, :name]}]
processing array...
v = id
a = []
v is a symbol
v = name
a = [:id]
v is a symbol
v = {:users=>[:id, :name]}
a = [:id, :name]
calling doit(v). v is a hash or an array
passed obj = {:users=>[:id, :name]}
processing hash...
k=users, v=[:id, :name], a=[]
passed obj = [:id, :name]
processing array...
v = id
a = []
v is a symbol
v = name
a = [:id]
v is a symbol
returning [:id, :name]
returning [[:users, :id], [:users, :name]]
returning [:id, :name, [:users, :id], [:users, :name]]
returning [[:board, :id], [:board, :name], [:column, :id], [:column, :name],
[:column, :users, :id], [:column, :users, :name]]
k=trello, v=[:id, :name], a=[[:friend, :id], [:friend, :name], [:meta, :board, :id],
[:meta, :board, :name], [:meta, :column, :id], [:meta, :column, :name],
[:meta, :column, :users, :id], [:meta, :column, :users, :name]]
passed obj = [:id, :name]
processing array...
v = id
a = []
v is a symbol
v = name
a = [:id]
v is a symbol
returning [:id, :name]
returning [[:friend, :id], [:friend, :name], [:meta, :board, :id],
[:meta, :board, :name], [:meta, :column, :id], [:meta, :column, :name],
[:meta, :column, :users, :id], [:meta, :column, :users, :name],
[:trello, :id], [:trello, :name]]
#=> [[:friend, :id], [:friend, :name], [:meta, :board, :id], [:meta, :board, :name],
[:meta, :column, :id], [:meta, :column, :name], [:meta, :column, :users, :id],
[:meta, :column, :users, :name], [:trello, :id], [:trello, :name]]