如何使用递归编程填充包含许多类别的列表框

我有一个类别表,设置为允许无限数量的子类别级别。 我想模仿以下内容: 在此处输入图像描述

应该澄清的是,子类别可以有子类别。 例如父母 – > 1级 – > 2级 – > 3级等

我的类别表有两列, CategoryNameParentID

在为产品分配正确的类别时,将使用此列表框。

我怎么写这个?

编辑

为了回应thedugas我不得不修改你的答案以适应我的情况。 我发现了一些需要修复的错误,但下面是一个最终的,有效的解决方案。

 protected void Page_Load(object sender, EventArgs e) { using (DataClasses1DataContext db = new DataClasses1DataContext()) { var c = db.Categories.Select(x => x); List categories = new List(); foreach (var n in c) { categories.Add(new Category() { categoryID = n.categoryID, title = n.title, parentID = n.parentID, isVisible = n.isVisible }); } List xx = new List(); foreach (Category cat in categories) { BuildCatString(string.Empty, cat, categories, xx); } ListBox1.DataSource = xx; ListBox1.DataBind(); } } private void BuildCatString(string prefix, Category cat, IEnumerable categories, List xx) { if (cat.parentID == 0) { xx.Add(cat.title); prefix = cat.title; } var children = categories.Where(x => x.parentID == cat.categoryID); if (children.Count() == 0) { return; } foreach (Category child in children) { if(prefix.Any()) { xx.Add(prefix + "/" + child.title); BuildCatString(prefix + "/" + child.title, child, categories, xx); } } } 

这是几乎完成的工作: 在此处输入图像描述

尼克在评论另一个问题时问我如何在不使用任何递归的情况下使用LINQ to Objects解决这类问题。 轻松完成。

假设我们有一个Dictionary ,它将ids映射到类别。 每个类别都有三个字段:Id,ParentId和Name。 让我们假设ParentId可以为null,以标记那些“顶级”的类别。

所需的输出是一系列字符串,其中每个字符串都是该类别的“完全限定”名称。

解决方案很简单。 我们首先定义一个辅助方法:

 public static IEnumerable CategoryAndParents(this Dictionary map, Id id) { Id current = id; while(current != null) { Category category = map[current]; yield return category; current = category.ParentId; } } 

而这个辅助方法:

 public static string FullName(this Dictionary map, Id id) { return map.CategoryAndParents(id) .Aggregate("", (string name, Category cat) => cat.Name + (name == "" ? "" : @"/") + name); } 

或者,如果您希望避免可能效率低下的天真字符串连接:

 public static string FullName(this Dictionary map, Id id) { return string.Join(@"/", map.CategoryAndParents(id) .Select(cat=>cat.Name) .Reverse()); } 

现在查询很简单:

 fullNames = from id in map.Keys select map.FullName(id); listBox.DataSource = fullNames.ToList(); 

不需要递归。

我想说如果可以的话,在SQL中使用递归CTE。 编辑:这是MS SQL> = 2005的递归CTE:

 ; WITH cte AS ( select CategoryId, CategoryName, ParentId, cast(CategoryName as varchar(max)) as xpath from categories where ParentId = 0 UNION ALL select c.CategoryId, c.CategoryName, c.ParentId, cast(p.xpath + '/' + c.CategoryName as varchar(max)) as xpath from categories c inner join cte p on p.CategoryId = c.ParentId ) select xpath from cte order by xpath 

如果你不能,那么这是一种方式:

 class Category { public int ParentId { get; set; } public int CategoryId { get; set; } public string CategoryName { get; set; } public static void BuildCatStringList(string prefix, Category c, IEnumerable categories, List catStrings) { if (c.ParentId == 0) { catStrings.Add(c.CategoryName); prefix = c.CategoryName; } var children = categories.Where(cats => cats.ParentId == c.CategoryId); if (children.Count() == 0) { return; } foreach (Category child in children) { catStrings.Add(prefix + "/" + child.CategoryName); BuildCatStringList(prefix + "/" + child.CategoryName, child, categories, catStrings); } } static void Main(string[] args) { List categories = new List(); categories.Add(new Category() { ParentId = 0, CategoryName = "CD-DVD-Video", CategoryId=1 }); categories.Add(new Category() { ParentId = 1, CategoryName = "DVD", CategoryId = 10 }); categories.Add(new Category() { ParentId = 1, CategoryName = "Video cassettes", CategoryId= 11 }); categories.Add(new Category() { ParentId = 0, CategoryName = "Computer Hardware", CategoryId= 2 }); categories.Add(new Category() { ParentId = 2, CategoryName = "CD & DVD", CategoryId = 12 }); categories.Add(new Category() { ParentId = 2, CategoryName = "CPU Coolers", CategoryId = 13 }); categories.Add(new Category() { ParentId = 2, CategoryName = "Cases", CategoryId = 14 }); categories.Add(new Category() { ParentId = 2, CategoryName = "Keyboards", CategoryId = 15 }); List x = new List(); foreach (Category cat in categories.Where(c => c.ParentId == 0)) { Category.BuildCatStringList(String.Empty, cat, categories, x); } } 

假设顶级类别的ParentID为NULL。 我会去:

  • 将数据保存在数据集Order By ParentID,CategoryName中。 让我们说dataset1

string MainCategory as string =“”;

 For(int i=0;i<=dataset1.CategoryTable.Rows-1;i++) { if (dataset1.CategoryTable[i]["ParentID"] == DBNull.value) { MainCategory= Convert.Tostring(dataset1.CategoryTable[i]["CategoryName"]); } else { // Add to the list List1.Add(MainCategory + Convert.Tostring(dataset1.CategoryTable[i]["CategoryName"])); } }