使用父ID C#将平面列表映射到分层列表

我有一个平面的类别列表,如以下类所示

public class FlatCategoryList { public List Categories { get; set; } } public class FlatCategory { public string ID { get; set; } public string Name { get; set; } public string ParentID { get; set; } } 

我正在尝试将我的平面类别列表映射到一个非常规的结构,如下所示:

 public class HieraricalCategoryList { public List Categories { get; set; } } public class Category { public string ID { get; set; } public string Name { get; set; } public string ParentID { get; set; } public List ChildCategories { get; set; } } 

我的问题是,实现这一点的最佳方法是什么,因为可能存在无限数量的子层?

 public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList) { var hieraricalCategoryList = new HieraricalCategoryList(); //Do something here to map the flat category list to the hierarichal one... return hieraricalCategoryList; } 

 public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList) { var categories = (from fc in flatCategoryList.Categories select new Category() { ID = fc.ID, Name = fc.Name, ParentID = fc.ParentID }).ToList(); var lookup = categories.ToLookup(c => c.ParentID); foreach(var c in categories) { // you can skip the check if you want an empty list instead of null // when there is no children if(lookup.Contains(c.ID)) c.ChildCategories = lookup[c.ID].ToList(); } return new HieraricalCategoryList() { Categories = categories }; } 

进行此转换的一种非常简单且高性能的方法是创建一个查找,在该查找中将ID值映射到应该是该ID值的子节点的节点。 可以在单个节点传递中创建此查找。 之后,您可以再次遍历所有节点,将其子集合分配为查找中其ID值的值。

请注意,如果查找映射到要转换为的类型的对象,而不是从中进行转换,则这会更简单。

 var lookup = list.Categories .Select(category => new Category() { ID = category.ID, Name = category.Name, ParentID = category.ParentID, }) .ToLookup(category => category.ParentID); foreach (var category in lookup.SelectMany(x => x)) category.ChildCategories = lookup[category.ID].ToList(); var newList = new HieraricalCategoryList() { Categories = lookup[null].ToList(), }; 

使用两遍解决方案。 这假设完整集合可以适合内存。 第一遍扫描平面类别列表,并构建一个类别字典,由ID索引。 此时子集合全为空,父属性为null。 然后第二遍再次扫描它们,并构建子集合并设置父属性。

未经测试的代码:

 var final = new Dictionary(); var rootCategories = new List(); // Pass 1 foreach (var flat in flatList) { Category cat = new Category() { ID = flat.ID, Name = flat.Name, parent = null } cat.Children = new List(); final[flat.ID] = cat; } // Pass 2 foreach (var flat in flatList) { // find myself -- must exist var self = final[flat.ID]; // find parent -- may not exist if (final.ContainsKey(flat.ParentID) { var parent = final[flat.ParentID]; parent.Children.Add(self); self.Parent = parent; } else { rootCategories.Add(self); } } 

这将有O(n)运行时间,因为它是两次线性扫描,有一些字典查找,即O(1)。

改进了建议的答案

 public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList) { var categories = (from fc in flatCategoryList.Categories select new Category() { ID = fc.ID, Name = fc.Name, ParentID = fc.ParentID }).ToList(); var lookup = categories.ToLookup(c => c.ParentID); foreach(var c in rootCategories)//only loop through root categories { // you can skip the check if you want an empty list instead of null // when there is no children if(lookup.Contains(c.ID)) c.ChildCategories = lookup[c.ID].ToList(); } //if you want to return only root categories not all the flat list //with mapped child categories.RemoveAll(c => c.ParentId != 0);//put what ever your parent id is return new HieraricalCategoryList() { Categories = categories }; }