所以我们有哈希数组
array = [
{id: 1, parent_id: 0},
{id: 2, parent_id: 1},
{id: 3, parent_id: 0},
{id: 4, parent_id: 2}
]
target_array = []
将该数组映射/排序为以下结果的最有效和红宝石方法是什么:
target_array = [
{id:1,children:
[{id: 2, children: [
{id:4, children:[]}]}]},
{id: 3, children:[]}
]
p.s.我能做的最多就是为每个项目迭代整个事物,并从已映射到target_array
的数组哈希中排除。
答案 0 :(得分:3)
你可以通过递归来解决这个问题:
@array = [
{id: 1, parent_id: 0},
{id: 2, parent_id: 1},
{id: 3, parent_id: 0},
{id: 4, parent_id: 2}
]
def build_hierarchy target_array, n
@array.select { |h| h[:parent_id] == n }.each do |h|
target_array << {id: h[:id], children: build_hierarchy([], h[:id])}
end
target_array
end
build_hierarchy [], 0
输出:
=> [{"id"=>1, "children"=>[{"id"=>2, "children"=>[{"id"=>4, "children"=>[]}]}]}, {"id"=>3, "children"=>[]}]
中的实例
答案 1 :(得分:2)
我会使用递归,但以下内容很容易转换为非递归方法。
首先构建一个哈希,将父母与子女联系起来(p2c
)。为此,请使用Hash#update(aka merge!
)的形式,该形式使用块来确定合并的两个哈希中存在的键的值:
@p2c = array.each_with_object({}) { |g,h|
h.update(g[:parent_id]=>[g[:id]]) { |_,ov,nv| ov+nv } }
#=> {0=>[1, 3], 1=>[2], 2=>[4]}
还有许多其他方法可以构建此哈希。这是另一个:
@p2c = Hash[array.group_by { |h| h[:parent_id] }
.map { |k,v| [k, v.map { |g| g[:id] }] }]
现在构造一个递归方法,其单个参数是父类:
def family_tree(p=0)
return [{ id: p, children: [] }] unless @p2c.key?(p)
@p2c[p].each_with_object([]) { |c,a|
a << { id:c, children: family_tree(c) } }
end
我们获得:
family_tree
#=> [ { :id=>1, :children=>
# [
# { :id=>2, :children=>
# [
# { :id=>4, :children=>[] }
# ]
# }
# ]
# },
# { :id=>3, :children=>[] }
# ]
最初构造哈希@p2c
应该会非常有效。
答案 2 :(得分:1)
这是我尝试使用哈希
的方法array = [
{id: 1, parent_id: 0},
{id: 2, parent_id: 1},
{id: 3, parent_id: 0},
{id: 4, parent_id: 2}
]
target_hash = Hash.new { |h,k| h[k] = { id: nil, children: [ ] } }
array.each do |n|
id, parent_id = n.values_at(:id, :parent_id)
target_hash[id][:id] = n[:id]
target_hash[parent_id][:children].push(target_hash[id])
end
puts target_hash[0]
<强>输出:强>
{:id=>nil, :children=>[{:id=>1, :children=>[{:id=>2, :children=>[{:id=>4, :children=>[]}]}]}, {:id=>3, :children=>[]}]}
答案 3 :(得分:1)
我认为最好的一个最多会有O(nlog(n))时间复杂度。我给出了我的非哈希值:
array = [
{id: 1, parent_id: 0},
{id: 2, parent_id: 1},
{id: 3, parent_id: 0},
{id: 4, parent_id: 2}
]
# This takes O(nlog(n)).
array.sort! do |a, b|
k = (b[:parent_id] <=> b[:parent_id])
k == 0 ? b[:id] <=> a[:id] : k
end
# This takes O(n)
target_array = array.map do |node|
{ id: node[:id], children: [] }
end
# This takes O(nlog(n))
target_array.each_with_index do |node, index|
parent = target_array[index + 1...target_array.size].bsearch do |target_node|
target_node[:id] == array[index][:parent_id]
end
if parent
parent[:children] << node
target_array[index] = nil
end
end
# O(n)
target_array.reverse.compact
# =>
# [{:id => 1, :children =>[{:id=>2,:children=> [ {:id=>4,
# :children=>[]}]}]},
# {:id=>3, :children=>[]} ]
因此我一般使用O(nlog(n))。
顺便说一句,当我简单地测试现有的解决方案时,我发现Gagan Gami的效率最高(略高于我的),我相信它也是O(nlog(n)),虽然不明显。但目前接受的解决方案需要O(n ^ 2)时间。