如何与LAMBDA订购亲子关系?

时间:2016-07-24 10:23:59

标签: c# linq recursion lambda tree

使用LAMBDA编写LINQ查询以在列表中首先放置父项(因为父子依赖项)的正确方法是什么?

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

  • ID Parent
  • A2 null
  • A1 A2
  • A5 A2(取决于A2)
  • A3 A2
  • A4 A5(取决于A5)

1 个答案:

答案 0 :(得分:0)

树遍历通常需要某种递归,并且由于C#作为一种语言不支持命名的lambda表达式(与命名函数表达式的JavaScript概念不同),我认为无法在纯LINQ中干净地执行此任务使用lambdas进行查询。

如果您愿意在外部声明您的函数委托,则很有可能。但是,此代码没有为构建树的传统递归方法提供明显的优势,但确实演示了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, A2
A3, A2
A5, A2
A4, A5