如何进行递归LINQ查询?

时间:2014-07-18 09:30:34

标签: c# linq recursion

我有一个递归数据结构,例如链表:

class Node
{
    private Node next;
    private int data;

    // (...)
    public Node Next
    {
        get
        {
            return next;
        }
    }

    public int Data
    {
        get
        {
            return data;
        }
    }
}

我想创建一个LINQ查询,它从列表的头部开始,然后遍历元素,即时收集数据。怎么做?

3 个答案:

答案 0 :(得分:3)

以下是我用来解析TreeView控件中所有节点的两个辅助类。

您可能会受到yield关键字用于根据您的需求进行调整的启发。

internal static IEnumerable<TreeNode> Descendants(this TreeNodeCollection c)
{
    foreach (var node in c.OfType<TreeNode>())
    {
        yield return node;

        foreach (var child in node.Nodes.Descendants())
        {
            yield return child;
        }
    }
}

例如:

var allCheckedNodes = myTreeView.Nodes.Descendants().Where(c => c.Checked);

答案 1 :(得分:2)

仅使用简单的LINQ查询就很难遍历任意复杂的数据结构。在某些时候,你将不得不“减少损失”并自己编写迭代器块 - 可能仅用于难以用标准LINQ表达的部分。

也就是说,对于您的链接列表示例,使用moreLinq,您可以执行以下操作:

MoreEnumerable.Generate(head, node => node.Next)
              .TakeWhile(node => node != null)

如果你想要递归的LINQ树遍历(或类似的),它会有很大的不同,但这里是一个样本(深度优先):

private static IEnumerable<Node> GetNodeAndDescendants(Node node)
{
   return new[] { node }.Concat(node.Children.SelectMany(GetNodeAndDescendants));
}

答案 2 :(得分:1)

通常可能无法使用常规LINQ扩展,但可以使用以下扩展方法:

public static IEnumerable<U> For<T, U>(this T obj, Func<T, U> extract, Func<T, bool> continueCondition, Func<T, T> step)
{
    while (!continueCondition(obj))
    {
        yield return extract(obj);
        obj = step(obj);
    }
}

从现在开始,您可以编写很酷的查询,例如:

head.For(n => n.SomeData, n => n != null, n => n.Next)
    .Select(n => n.Data)
    // More LINQ here

例如,让我们总结从1到20的所有偶数(用鲜明的linq-maniac方式)

int sum = 1.For(n => n, n => n <= 20, n => n + 1)
    .Where(n => n % 2 == 0)
    .Aggregate((a, b) => a + b);