首先全面披露。我试图在这个问题上解决这个问题,但我想重新发布一下,希望能在Ruby中得到一些帮助:
best way to sort an array of objects by category and infinite subcategory
我做了一个微弱的尝试,但是甚至无法接近,甚至不值得展示。以下是我的尝试。如果有人可以就此做出一些好的指示,对我来说意味着世界。
data = [{id: 1, name: "parent test 1", parent_id: nil, top_level_category_id: nil},
{id: 2, name: "test 2", parent_id: 1, top_level_category_id: 1},
{id: 3, name: "test 3", parent_id: 1, top_level_category_id: 1},
{id: 4, name: "parent test 4", parent_id: nil, top_level_category_id: nil},
{id: 5, name: "test 5", parent_id: 3, top_level_category_id: 4},
{id: 6, name: "test 6", parent_id: 4, top_level_category_id: 4},
{id: 7, name: "test 7", parent_id: 4, top_level_category_id: 4}]
这是我希望实现的目标
parent test 1
test 2
test 3
test 5
parent test 2
test 6
test 7
-
ord_cat = {}
for item in data
if item[:parent_id] == nil
ord_cat[item[:id]] = {:name => item[:name], :children => {}}
end
end
# fill child directories
for item in data
if item[:parent_id] != nil
ord_cat[item[:top_level_category_id]][:children].merge!({item[:id] => item[:name]})
end
end
puts ord_cat
这是输出
{1=>{:name=>"parent test 1", :children=>{2=>"test 2", 3=>"test 3", 5=>"test 5"}}, 4=>{:name=>"parent test 4", :children=>{6=>"test 6", 7=>"test 7"}}}
这显然没有正确地嵌套“测试5”。我对这个物体的结构并不感到兴奋。
答案 0 :(得分:1)
我们可以为每个节点构建祖先列表并根据该列表进行排序,实际上是对树的深度优先遍历。
有点长的解决方案,但会解决我相信的问题。已经多次使用哈希以避免多次扫描阵列。
data = [{id: 1, name: "parent test 1", parent_id: nil, top_level_category_id: nil},
{id: 2, name: "test 2", parent_id: 1, top_level_category_id: 1},
{id: 3, name: "test 3", parent_id: 1, top_level_category_id: 1},
{id: 4, name: "parent test 4", parent_id: nil, top_level_category_id: nil},
{id: 5, name: "test 5", parent_id: 3, top_level_category_id: 4},
{id: 6, name: "test 6", parent_id: 4, top_level_category_id: 4},
{id: 7, name: "test 7", parent_id: 4, top_level_category_id: 4}]
# Amount of indentation for printing each node's nesting
INDENTATION_PER_LEVEL = 1
id_to_data_map = {}
id_to_parent_id_map = {}
data.each { |d|
id_to_data_map[d[:id]] = d
id_to_parent_id_map[d[:id]] = d[:parent_id]
}
data_with_ancestors = {}
data.each do |record|
ancestors = [record[:name]]
# Temporary parent
parent = record
while true do
parent_id = id_to_parent_id_map[parent[:id]]
break if parent_id.nil? # Hit the root - get out.
parent = id_to_data_map[parent_id]
ancestors << parent[:name]
end
# Construct a list of ancestors for the node, with the oldest ancestor first.
data_with_ancestors[record[:name]] = ancestors.reverse
end
# Sort the flattened list based on the ancestor string constructed by joining all the parent names.
sorted_list = data_with_ancestors.sort_by {|name, ancestors| ancestors.join(" ")}
# Add indentation for the record names based on their nesting in the tree.
print_info = sorted_list.collect {|name, ancestors| (" " * (ancestors.size - 1) * INDENTATION_PER_LEVEL) + name}
print_info.each { |record| puts record }