带子项的订购列表

如果在其他地方被问到这个问题,我很抱歉,但是我已经找到了合适的答案,但是我发现的大多数信息仅允许单个子项目。

我正在尝试编写一个在树视图样式界面中显示信息的程序。 我面临的问题是我正在从后端数据库中读取以下类:

public class InputClass { public int id { get; set; } public string text { get; set; } public string icon { get; set; } public int? parentId { get; set; } } 

我正在尝试将其转换为以下类型的列表:

 public class OutputClass { public int id { get; set; } public string text { get; set; } public string icon { get; set; } public List children { get; set; } } 

如您所见,子属性将在找到它的父项时填充。

作为示例 – 以下列表:

 var inputList = new List(); inputList.Add(new InputClass() { id = 1, text = "Item #1"}); inputList.Add(new InputClass() { id = 2, text = "Item #2" }); inputList.Add(new InputClass() { id = 3, text = "Item #3" }); inputList.Add(new InputClass() { id = 4, text = "SubItem #1", parentId = 1 }); inputList.Add(new InputClass() { id = 5, text = "SubItem #2", parentId = 1 }); inputList.Add(new InputClass() { id = 6, text = "SubItem #3", parentId = 2 }); 

应输出为:

 Item #1 ----SubItem #1 ----SubItem #2 Item #2 ----SubItem #3 Item #3 

子列表中元素的数量不应仅限于一个。 有关如何正确排序的任何想法?

 var mapping = inputList // for each input element, capture the parent id and create the respective output object .Select(input => new { ParentId = input.parentId, Obj = new OutputClass() { id = input.id, text = input.text, icon = input.icon, children = new List() } }) // create a dictionary so we can look up the elements by id .ToDictionary(x => x.Obj.id); // create target list List output = new List(); // loop through all elements foreach (var x in mapping.Values) { // if the element has a parent id if (x.ParentId.HasValue) { // find the parent object … OutputClass parentObj = mapping[x.ParentId.Value].Obj; // … and add this object to the parent's child list parentObj.children.Add(x.Obj); } else { // otherwise this is a root element, so add it to the target list output.Add(x.Obj); } } 

结果将是一个包含具有相应层次结构的输入元素的列表。

这是线性时间的解决方案,它只会循环两次项目。 此外,它还支持多个级别的层次结构,因此您可以使用父ID为5生成第三级别等。


要生成输出,您可以编写一个递归函数,如下所示:

 public static void Print(IEnumerable elements, string indent="") { foreach (OutputClass element in elements) { Console.WriteLine("{0}{1} {2}", indent, element.id, element.text); Print(element.children, indent + " "); } } 

对于您的输入,这会产生以下结果:

 1 Item #1 4 SubItem #1 5 SubItem #2 2 Item #2 6 SubItem #3 3 Item #3 

仅作为示例,以下输入列表使用与上面相同的转换代码生成下面的输出:

 var inputList = new List() { new InputClass() { id = 1, text = "Item 1" }, new InputClass() { id = 2, text = "Item 2" }, new InputClass() { id = 3, text = "Item 3" }, new InputClass() { id = 4, text = "SubItem 1.1", parentId = 1 }, new InputClass() { id = 5, text = "SubItem 1.2", parentId = 1 }, new InputClass() { id = 6, text = "SubItem 2.1", parentId = 2 }, new InputClass() { id = 7, text = "SubItem 2.2", parentId = 2 }, new InputClass() { id = 8, text = "SubItem 1.2.1", parentId = 5 }, new InputClass() { id = 9, text = "SubItem 1.2.2", parentId = 5 }, new InputClass() { id = 10, text = "SubItem 1.2.1.1", parentId = 8 }, new InputClass() { id = 11, text = "SubItem 2.1.1", parentId = 6 }, new InputClass() { id = 12, text = "SubItem 2.1.1.1", parentId = 11 }, new InputClass() { id = 13, text = "SubItem 2.1.1.1.1", parentId = 12 }, new InputClass() { id = 14, text = "SubItem 2.1.1.1.2", parentId = 12 } }; 

输出:

 1 Item 1 4 SubItem 1.1 5 SubItem 1.2 8 SubItem 1.2.1 10 SubItem 1.2.1.1 9 SubItem 1.2.2 2 Item 2 6 SubItem 2.1 11 SubItem 2.1.1 12 SubItem 2.1.1.1 13 SubItem 2.1.1.1.1 14 SubItem 2.1.1.1.2 7 SubItem 2.2 3 Item 3 

以下代码应该打印出您需要的内容:

 static void Main(string[] args) { var inputList = new List(); inputList.Add(new InputClass() { id = 1, text = "Item #1" }); inputList.Add(new InputClass() { id = 2, text = "Item #2" }); inputList.Add(new InputClass() { id = 3, text = "Item #3" }); inputList.Add(new InputClass() { id = 4, text = "SubItem #1", parentId = 1 }); inputList.Add(new InputClass() { id = 5, text = "SubItem #2", parentId = 1 }); inputList.Add(new InputClass() { id = 6, text = "SubItem #3", parentId = 2 }); var outputList = inputList .Where(i => !i.parentId.HasValue) // Just get the parents .Select(i => new OutputClass() { id = i.id, icon = i.icon, text = i.text, children = inputList .Where(x => x.parentId == i.id) .Select(x => new OutputClass() { id = x.id, icon = x.icon, text = x.text, }).ToList() }).ToList(); foreach (var output in outputList) { Console.WriteLine(output.text); output.children.ForEach(c => Console.WriteLine($"\t {c.text}")); } Console.ReadLine(); } 

输出是:

 Item #1 SubItem #1 SubItem #2 Item #2 SubItem #3 Item #3