我有一个递归数据结构,例如链表:
class Node
{
private Node next;
private int data;
// (...)
public Node Next
{
get
{
return next;
}
}
public int Data
{
get
{
return data;
}
}
}
我想创建一个LINQ查询,它从列表的头部开始,然后遍历元素,即时收集数据。怎么做?
答案 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);