使用 LINQ 从根节点中选择所有系列
本文关键字:系列 选择 LINQ 根节点 使用 | 更新日期: 2024-11-05 21:03:26
假设我有一个类别,它可以有无限的孩子,每个孩子也可以有无限的孩子。
只是好奇,有没有办法使用 LINQ 检索根节点的所有系列?
在 C# 中处理递归结构有两种常用方法 - 使用 yield return
和编写递归函数。我更喜欢第二种方式,这里有一个例子:
public static class TreeUtils {
public static IEnumerable<T> GetAllNodes<T>(
this T node
, Func<T,IEnumerable<T>> f)
{
return GetAllNodes(new[] {node}, f);
}
public static IEnumerable<T> GetAllNodes<T>(
this IEnumerable<T> e
, Func<T,IEnumerable<T>> f)
{
return e.SelectMany(c => f(c).GetAllNodes(f)).Concat(e);
}
}
可以按如下方式使用此实用程序类:
class TreeNode<T> {
public T Content {get; set;}
public IEnumerable<TreeNode<T>> Dependents {get;set;}
}
foreach (TreeNode node in TreeUtils.GetAllNodes(root, n => n.Dependents)) {
Console.WriteLine(node.Content);
}
一种有点欺骗性的方式是使用"递归"lambda:
using System;
using System.Collections.Generic;
public class Program {
class Node {
public int Data;
public IEnumerable<Node> Dependents { get; set; }
}
public static void Main() {
var root = Create(
10
, Create(5, Create(3), Create(7, Create(6), Create(8)))
, Create(20, Create(15), Create(30, Create(28), Create(40)))
);
// We cannot combine the declaration and definition here
Func<Node,IEnumerable<Node>> all = null;
// The recursive magic is in the following line
all = n => n.Dependents.SelectMany(d => all(d)).Concat(new[] {n});
// Here is how you can use it
foreach (var node in all(root)) {
Console.WriteLine(node.Data);
}
}
// Helper function for creating tree nodes
private static Node Create(int data, params Node[] nodes) {
return new Node { Data = data, Dependents = nodes };
}
}
linq 非常依赖的 Lambdas 不支持以直观的方式执行此类操作所需的递归;但是,使用 let 和 y 组合器,您可以以非直观的方式进行递归。下面是一个复杂的例子:
http://blogs.msdn.com/b/lukeh/archive/2007/10/01/taking-linq-to-objects-to-extremes-a-fully-linqified-raytracer.aspx
希望有人能想出一个更简洁的。如果是这样,请选择它们。