如何使用LAMBDA订购亲子关系

本文关键字:关系 何使用 LAMBDA | 更新日期: 2023-09-27 17:58:29

使用LAMBDA编写LINQ查询以将父项(由于父子依赖关系)放在列表的第一位的正确方法是什么?

例如,预期的输出应该是一个有序列表(名为"层次结构"的对象类型),其中包含所有字段ID,类型字符串的父项):

  • ID父项
  • A2空
  • A1 A2
  • A5 A2(取决于A2)
  • A3 A2
  • A4 A5(取决于A5)

如何使用LAMBDA订购亲子关系

树遍历通常需要某种递归,由于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