我想获得技巧和示例,说明如何转换这样的不同结构:
x <- 2
x * prod(c(1.1, 1.2, 1.11, 1.21))
# [1] 3.545784
像这样进入数组:
h = {
friend: [:id, :name],
meta: {
board: [:id, :name],
column: [:id, :name, users: [:id, :name]]
},
trello: [:id, :name]
}
此数组的每个元素都是完整路径。
答案 0 :(得分:3)
这是非常标准的Tree traversal problem。您可以通过递归使用DFS:
# 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
它输出:
[: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]
答案 1 :(得分:1)
代码
def doit(obj)
case obj
when Hash
obj.each_with_object([]) do |(k,v),a|
case v
when Symbol
a << v
else
doit(v).each { |aa| a << [k, *aa] }
end
end
else
obj.each_with_object([]) do |v,a|
case v
when Symbol
a << v
else
doit(v).each { |aa| a << aa }
end
end
end
end
示例
对于问题中给出的哈希h
,结果如下。
doit(h)
#=> [[: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]]
说明
通过递归方法执行的操作总是很难解释。以我的经验,最好的方法是使用puts
语句添加代码。但是,这本身是不够的,因为在查看输出时,很难跟踪获得特定结果的递归级别,方法何时调用自身以及返回的自身版本。解决方案是缩进和缩进结果,这是我在下面所做的。
INDENT = 4
@col = -INDENT
def indent
@col += INDENT
end
def undent
@col -= INDENT
end
def pu(s)
print " "*@col
puts s
end
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
以# rem
结尾的行(“删除”)是我添加到方法中的行。
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]]