2012-05-13 22 views
7

私はこのような階層データのリストを持っているツリーのリーフ内のデータを - >info = nulllinqクエリで階層データの深さを取得する方法は?</p> <pre><code>var list = new List<Data>(){some data...} class Data { public int number; public List<Data> info; } </code></pre> <p>注:

例:

数字は、Dataクラスのnumber propertyある

--1 
     --11 
    --2 
     --21 
     --22 
     --23 
     --24 
    --3 
     --31 
     --32 
      --321 
      --322 
    --4 
     --41 
     --42 

trの最大深度を知る方法ee linqクエリ(非再帰的メソッドまたはループ)のデータのリスト?この例では、最大レベルの

は321322

ありがとう3です。

+5

LINQは、データの線形シーケンスではなく、再帰的なデータ構造のために設計されています。再帰的な方法で何が問題になっていますか? – dtb

+0

いいえ間違いなく、私はlinqでこの問題を解決するのが好奇心です。 –

+0

@RezaArab、私はこれがlinqでも可能であるとは思っていません。 –

答えて

0

LINQとSQLはフラットなデータ構造で動作します。それらは再帰的なデータ構造のために設計されていません。

LINQ to Entitiesでは、運が悪いと思います。各ノードにサブツリーの深さを格納し、ノードを挿入/削除するたびに再帰的に更新します。

オブジェクトへのLINQで

、あなたは、ツリー内のすべてのパスを返す再帰的な拡張メソッドを定義し、最長パスの長さは取ることができる:

var result = root.Paths().Max(path => path.Length); 

public static IEnumerable<Data[]> Paths(this Data data) 
{ 
    return Paths(data, new[] { data }); 
} 

private static IEnumerable<Data[]> Paths(Data data, Data[] path) 
{ 
    return new[] { path }.Concat((data.info ?? Enumerable.Empty<Data>()) 
    .SelectMany(child => Paths(child, path.Concat(new[] { child }).ToArray()))); 
} 
1

すべてのLINQ演算子をなんらかの方法でループを使用するので、要件がループでない場合はlinqで解決することはできません。

再帰なしで可能です。スタックが必要です。

public static IEnumerable<Tuple<int, T>> FlattenWithDepth<T>(T root, Func<T, IEnumerable<T>> children) { 
    var stack = new Stack<Tuple<int, T>>(); 

    stack.Push(Tuple.Create(1, root)); 

    while (stack.Count > 0) { 
     var node = stack.Pop(); 

     foreach (var child in children(node.Item2)) { 
      stack.Push(Tuple.Create(node.Item1+1, child)); 
     } 
     yield return node; 
    } 
} 

あなたのLINQクエリのような何かが、その後

FlattenWithDepth(root, x => x.info ?? Enumerable.Empty<Data>()).Max(x => x.Item1); 

**編集(ごめん検証するために利用可能なコンパイラを持っていない)になります。ちょうどあなたがあなたがDBにそれを使用する必要がある場合は、私は木の深さを保存するために、あなたのDBに追加の列を追加することをお勧め

list.SelectMany(y => FlattenWithDepth(y, x => x.info ?? Enumerable.Empty<Data>())) 
    .Max(x => x.Item1) 
0

**複数のルートを持っていたことを見て、その深さの変化は、いくつかの状況があります。

新しい要素を追加する
  1. 、その深さはFatherDepth + 1
  2. で削除します。これは、カスケード関係である場合があり、削除に問題はありませんが、あなたが子供の深さを更新するために再帰クエリを記述する必要がありますカスケードいない場合。

深さを見つけるには、最大深度値を見つけるためのクエリを実行してください。

1

以下が働くだろう:

internal static class ListDataExtension 
{ 
    public static int MaxDepthOfTree(this List<Data> dataList) 
    { 
     return dataList.Max(data => data.MaxDepthOfTree); 
    } 
} 
internal class Data 
{ 
    public int number; 
    public List<Data> info; 

    public int MaxDepthOfTree 
    { 
     get 
     { 
      return GetDepth(1); 
     } 
    } 

    int GetDepth(int depth) 
    { 
     if (info == null) 
      return depth; 
     var maxChild = info.Max(x => x.GetDepth(depth)); 
     return maxChild + 1; 
    } 
} 

は、それからちょうど呼び出す:

var maxDepth = list.MaxDepthOfTree();