将嵌套列表展开到一个平面列表中?

时间:2016-10-17 17:15:14

标签: c# list recursion

我将一系列对象存储到具有非常简单结构的数据库中。代表作为模型,它们看起来类似于

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++;
    }
}

0 个答案:

没有答案