無制限の子を持つことができるカテゴリがあり、各子も無制限の子を持つことができると仮定します。
興味深いことに、LINQ を使用してルート ノードのすべてのファミリを取得する方法はありますか?
C# で再帰構造を処理するにはyield return
、再帰関数を使用する方法と記述する方法の 2 つの一般的な方法があります。私は 2 番目の方法を好みます。例を次に示します。
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);
}
「再帰的な」ラムダを使用するのは、やや不正な方法です。
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 が非常に依存しているラムダは、直感的な方法でそのようなことを行うために必要な再帰をサポートしていません。ただし、let と y コンビネーターを使用すると、非直感的な方法でそれを行うことができます。複雑な例を次に示します。
うまくいけば、誰かがより簡潔なものを考え出すでしょう。もしそうなら、それらを選んでください。