こんにちは、次のタイプのツリーがあるとしましょう
public class Element
{
public List<Element> element;
}
木の根は
Element root = GetTree();
再帰を使用してこのツリーの長さを確認できることは知っていますが、linq を使用してこのツリーの長さを確認することは可能ですか?
すべての要素を再帰的に取得する拡張メソッドを作成できます。
var allElements = root.element.Traverse(el => el.element);
例えば:
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
新しい拡張メソッドを追加します。
public static int CountX(this Element e)
{
int temp = 0;
if (e.element != null)
{
temp = e.element.Count;
e.element.ForEach(q => temp += q.CountX());
}
return temp;
}
そしてそれを次のように呼びます。
int depthCount= a.CountX();
私の知る限り、再帰的なラムダをそのまま使用することはできないため、再帰的なLinqを使用することはできません。
私が与えることができる最も独創的な答えは、再利用可能なFixpoint演算子に基づく再帰的なラムダ式に基づいています。ほとんどのLinqメカニズムが見つかります。しかし、私は、不動点の部分が純粋なLinqの答えがない理由であると思います。
public static class FixPoint
{
// Reusable fixpoint operator
public static Func<T, TResult> Fix<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> f)
{
return t => f(Fix<T, TResult>(f))(t);
}
}
public class Element
{
public List<Element> element;
public int CalculateMaxDepth()
{
return FixPoint.Fix<List<Element>, int>(
// recursive lambda
f =>
listElement => listElement == null || listElement.Count == 0
? 0
: 1 + listElement.Select(e => f(e.element)).Max())
(this.element);
}
[Test]
public void myTest()
{
var elt = new Element() { element = new List<Element> { new Element() { element = new List<Element> { new Element() { element = new List<Element> { new Element() } } } } } };
Assert.AreEqual(3, elt.CalculateMaxDepth());
}
}