使用LAMBDA编写LINQ查询以将父项(由于父子依赖关系)放在列表的第一位的正确方法是什么?
例如,预期的输出应该是一个有序列表(名为"层次结构"的对象类型),其中包含所有字段ID,类型字符串的父项):
- ID父项
- A2空
- A1 A2
- A5 A2(取决于A2)
- A3 A2
- A4 A5(取决于A5)
树遍历通常需要某种递归,由于C#作为一种语言不支持命名lambda表达式(与JavaScript中命名函数表达式的概念不同),我想不出任何方法可以使用lambda在纯LINQ查询中干净地执行此任务。
如果您愿意从外部声明您的函数委托,这是完全可能的。然而,与构建树的传统递归方法相比,这段代码没有明显的优势,但确实演示了LINQ/lambda版本的实现。
下面是一个使用递归和查找表的例子(为了提高效率):
IEnumerable<ItemType> items = new[]
{
new ItemType() { ID = "A4", ParentID = "A5"},
new ItemType() { ID = "A5", ParentID = "A2"},
new ItemType() { ID = "A1", ParentID = "A2"},
new ItemType() { ID = "A3", ParentID = "A2"},
new ItemType() { ID = "A2", ParentID = null },
};
var childrenLookup = items.ToLookup(i => i.ParentID);
Func<ItemType, IEnumerable<ItemType>> preOrderTraverse = null;
preOrderTraverse = new Func<ItemType, IEnumerable<ItemType>>(item =>
{
var curNode = Enumerable.Repeat(item, 1);
var childNodes = childrenLookup[item.ID]
.OrderBy(i => i.ID) // Sort siblings by ID
.SelectMany(preOrderTraverse);
return Enumerable.Union(curNode, childNodes);
});
var preOrderTraversal = childrenLookup[null].SelectMany(preOrderTraverse);
foreach(var item in preOrderTraversal)
Console.WriteLine($"{item.ID}, {item.ParentID}");
代码的输出是:
A2,A1,A2A3,A2A5,A2A4,A5