Мне пришлось исследовать проблему, с рекурсивной и нерекурсивной. Я поставил здесь 2 варианта:
"parend_id" = "head_id" # for those examples
Recursivly:
require 'pp'
nodes = [{"id"=>"1", "name"=>"User №1 Pupkin1", "head_id"=>nil},
{"id"=>"2", "name"=>"User №2 Pupkin2", "head_id"=>"1"},
{"id"=>"3", "name"=>"User №3 Pupkin3", "head_id"=>"2"}]
def to_tree(nodes, head_id = nil)
with_head, without_head = nodes.partition { |n| n['head_id'] == head_id }
with_head.map do |node|
node.merge('children' => to_tree(without_head, node['id']))
end
end
pp to_tree(nodes)
Плюсы:
Минусы:
- Ruby потерпит неудачу , если у нас будет > = 3000 узлов (это происходит из-за того, что у ruby есть ограничение стека для точек (функций), когда рубин требует повторной настройки обратно) Если иметь «pp» для вывода , он не будет работать на > = 200 узлов
Не рекурсивно, с циклом:
require 'pp'
nodes = [{"id"=>"1", "name"=>"User №1 Pupkin1", "head_id"=>nil},
{"id"=>"2", "name"=>"User №2 Pupkin2", "head_id"=>"1"},
{"id"=>"3", "name"=>"User №3 Pupkin3", "head_id"=>"2"}]
def to_tree(data)
data.each do |item|
item['children'] = data.select { |_item| _item['head_id'] == item['id'] }
end
data.select { |item| item['head_id'] == nil }
end
pp to_tree(nodes)
Плюсы:
Минусы:
- мы модифицируем объект Я, это недостаточно хорошо.
Результат обоих способов:
[{"id"=>"1",
"name"=>"User №1 Pupkin1",
"head_id"=>nil,
"children"=>
[{"id"=>"2",
"name"=>"User №2 Pupkin2",
"head_id"=>"1",
"children"=>
[{"id"=>"3",
"name"=>"User №3 Pupkin3",
"head_id"=>"2",
"children"=>[]}]}]}]
Резюме
Для производства лучше использовать второй способ, возможно, есть более оптимальный способ реализовать его.
Надеюсь, что написанное будет полезно