我将一系列对象存储到具有非常简单结构的数据库中。代表作为模型,它们看起来类似于
public SiteMenuItem
{
public int Id {get;set;}
public string Name {get;set;}
public int? ParentId {get;set;}
public int? Order {get;set;}
public virtual List<SiteMenuItem> Children {get;set;} //null on initialization
}
当我从数据库中检索这些值时,我将这些值转换为嵌套列表树状结构,以便在我们的Web应用程序中使用。我这样做的方式类似于:
private static List<SiteMenuItem> GetChildren(List<SiteMenuItem> menu)
{
// For every SiteMenuItem with a parentId, place the child under their parent.
menu.ForEach(menuItem => menuItem.Children = menu.Where(n => n.ParentId == menuItem.Id).ToList());
// Remove all orphaned items.
menu.RemoveAll(n => n.ParentId != null);
return menu;
}
此功能非常适合将我的平面列表转换为分层项列表。但是,我试图弄清楚如何反过来。
我需要弄清楚如何遍历项目列表(可能递归?)并将它们返回到已正确填充ParentId
的项目的平面列表。
这样做的最佳方式是什么?
修改
问题变得更加复杂,因为我还需要跟踪项目的存储顺序。例如,给定以下层次结构,我需要设置正确的顺序。
以下对象:
[
{
"Id":1,
"Name":"Menu Item 1",
"Children":[
{
"Id":2,
"Name":"Sub Menu Item 1",
"Children":[
]
},
{
"Id":3,
"Name":"Sub Menu Item 2",
"Children":[
]
}
]
},
{
"Id":4,
"Name":"Menu Item 2",
"Children":[
]
},
{
"Id":5,
"Name":"Menu Item 3",
"Children":[
{
"Id":6,
"Name":"Sub Menu Item 1",
"Children":[
{
"Id":7,
"Name":"Sub Menu Item 2"
}
]
},
{
"Id":8,
"Name":"Sub Menu Item 1",
"Children":[
]
}
]
}
]
将转变为:
[
{
"Id":1,
"Name":"Menu Item 1",
"Parent":"",
"Order":1
},
{
"Id":2,
"Name":"Sub Menu Item 1",
"Parent":1,
"Order":1
},
{
"Id":3,
"Name":"Sub Menu Item 2",
"Parent":1,
"Order":2
},
{
"Id":4,
"Name":"Menu Item 2",
"Parent":"",
"Order":2
},
{
"Id":5,
"Name":"Menu Item 3",
"Parent":"",
"Order":3
},
{
"Id":6,
"Name":"Sub Menu Item 1",
"Parent":5,
"Order":1
},
{
"Id":7,
"Name":"Sub Sub Menu Item 1",
"Parent":6,
"Order":1
},
{
"Id":8,
"Name":"Sub Menu Item 2",
"Parent":5,
"Order":2
}
]
视觉上菜单会看到这样的
Menu Item 1 | Menu Item 2 | Menu Item 3
| |
Sub1 - Sub2 Sub1 - Sub2
/
SubSub1
孩子们应该总是在原始列表(数组)中知道他们的顺序。
编辑2
我创建了一个基于链接[DUPLICATE]的修改后的解决方案,它允许我保持正确的排序(虽然方式略有不同),它允许我跟踪每个节点的正确父级。
public static IEnumerable<SiteMenuItemEditViewModel> FlattenItems(IEnumerable<SiteMenuItemEditViewModel> parents)
{
var stack = new Stack<SiteMenuItemEditViewModel>();
var order = 0;
foreach (var item in parents.Reverse())
{
item.parentId = null;
stack.Push(item);
}
while (stack.Count > 0)
{
var current = stack.Pop();
current.order = order;
current.menuItems.Reverse();
yield return current;
foreach (var child in current.children)
{
child.parentId = current.id;
stack.Push(child);
}
order++;
}
}