列表<对象>的递归读取

本文关键字:递归 读取 对象 列表 | 更新日期: 2023-09-27 18:36:08

我有List<Object>的结构,具体来说它是一个"CategoryItem"对象。这是我对"类别项"对象的声明。

public class CategoryItem
{
    public string Name { get; set; }
    public int CategoryID {get; set;}
    public int ParentID {get; set; }
    public List<CategoryItem> SubCategory {get; set;}
}

这是我的示例数据结构:

[0] CategoryID: 249
Name: "WelcomeNC"
ParentID: 0
SubCategory: length=4
    [0] CategoryID: 250
        Name: "CNC"
        ParentID: 249
        SubCategory: length=0
    [1] CategoryID: 251
        Name: "Production"
        ParentID: 249
        SubCategory: length=0
    [2] CategoryID: 252
        Name: "Administrative"
        ParentID: 249
        SubCategory: length=1
            [0] CategoryID: 261
                Name: "NPower"
                ParentID: 252
                SubCategory: length=0
    [3] CategoryID: 253
        Name: "Help"
        ParentID: 249
        SubCategory: length=1
            [0] CategoryID: 254
                Name: "7"
                ParentID: 253
                SubCategory: length=1
                    [0] CategoryID: 255
                        Name: "CHLK"
                        ParentID: 254
                        SubCategory: length=0
[1] CategoryID: 111
Name: "First"
ParentID: 0
SubCategory: length=0

我的问题是,我如何步入我声明的每个"类别项"对象:

List<CategoryItem> categoryItems = new List<CategoryItem>();

这样我就可以像这样在 html 的无序列表中显示它

  • 欢迎北卡罗来纳州
    • 数控
    • 生产
    • 行政
      • NPower
    • 帮助
      • 7
        • 查尔克
  • 第一

有没有办法做到这一点?

列表<对象>的递归读取

如果您的 CategoryItem 不包含其子项的列表(如问题的第一个版本),我将首先构建一个字典,为每个 CategoryID 提供所有子类别项,然后使用此字典递归打印所有项目,并从父项"0"开头。假设 Print 是打印与项目关联的数据的指令,并且它将缩进级别作为唯一参数,则代码将如下所示:

    public static void PrintItems(List<CategoryItem> items)
    {
        Dictionary<string, List<CategoryItem>> dictOfChildren = new Dictionary<string, List<CategoryItem>>();
        // loop through all the items grouping them according to their ParentID
        foreach (CategoryItem anItem in items)
        {
            List<CategoryItem> children;
            if (!dictOfChildren.TryGetValue(anItem.ParentID, out children))
            {
                children = new List<CategoryItem>();
                dictOfChildren[anItem.ParentID] = children;
            }
            children.Add(anItem);
        }
        // recursively print all the items starting from the ones with ParentID = 0
        // the dictionary is passed to the method in order to be able to find the children of each item
        PrintItems(dictOfChildren["0"], dictOfChildren, 0);
    }
    private static void PrintItems(List<CategoryItem> list, Dictionary<string, List<CategoryItem>> dictOfChildren, int levelOfIndentation)
    {
        foreach (CategoryItem anItem in list)
        {
            // first print the current item
            anItem.Print(levelOfIndentation);
            // then recursively print all its children
            List<CategoryItem> children;
            if (dictOfChildren.TryGetValue(anItem.CategoryID, out children) &&
                children.Count > 0)
                PrintItems(children, dictOfChildren, levelOfIndentation + 1);
        }
    }

它不是真正的面向对象,但这应该给你一个关于要遵循的方向的提示。

编辑:

我看到您编辑了问题,现在您已经添加了子类别属性。这使事情变得更加简单,您可以简单地执行以下操作:

public static void PrintItems(List<CategoryItem> items)
{
    // call a recursive method passing 0 as level of indentation
    PrintItems(items, 0);
}
public static void PrintItems(List<CategoryItem> items, int levelOfIndentation)
{
    foreach (CategoryItem anItem in items)
    {
        // print the currentItem
        anItem.Print(levelOfIndentation);
        // increment the level of indentation and callk the same method for the children
        PrintItems(anItem.SubCategory, levelOfIndentation + 1);
    }
}

也许看看 TreeView 控件? http://msdn.microsoft.com/en-US/library/7A9swst5(v=vs.80).aspx

ASP.NET TreeView 控件旨在以分层结构向用户显示数据。用户可以打开单个节点,而这些节点又可以包含子节点。控件适用于显示 XML 数据,但可用于可在层次结构中表示的任何数据。

我想这将是你想要的。

否则,需要

循环访问列表中的每个项目,并递归处理每个可能具有也可能没有更多子项的子项。 这很棘手,但只是一开始。

一个简单但不是最优但简单的解决方案是迭代列表,对于每个项目,您计算在 0 之前调用其父 id 的次数。因此,您就知道您的<li>必须具有多少级标识。

您需要创建一个"呈现"类别项的递归方法。此方法需要知道级别或当前深度,以便呈现以更正缩进:

private void RenderCategory(HtmlTextWriter writer, CategoryItem item, int level)
{
  writer.Write("<li style='padding-left: {0}px'>{1}</li>", 
    level * 5,
    HttpUtility.HtmlEncode(item.Name));
  int nextLevel = ++level;
  foreach (CategoryItem child in item.SubCategories)
  { 
    RenderCategory(writer, child, nextLevel);
  }
}

阅读递归。那里有相当多的样本。维基百科上的那些很简单,但原理是相同的:在一个"级别"上解决问题,然后在每个子级别上递调用相同的方法。