簡體   English   中英

如何使用linq查詢獲取層次數據的深度?

[英]How to get depth of hierarchical data with linq query?

我有一個像這樣的分層數據列表:

var list = new List<Data>(){some data...}

class Data
{
    public int number;
    public List<Data> info;
}

注意:樹的葉子中的數據 - > info = null

例:

numbers是Data類的number property

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

如何通過linq查詢(非遞歸方法或for循環)知道樹的最大深度到數據列表?

在此示例中,321,322的最大級別為3

謝謝。

LINQ和SQL在平面數據結構上運行; 它們不是為遞歸數據結構而設計的。

有了LINQ to Entities,我相信你運氣不好。 將子樹的深度存儲在每個節點中,並在插入/刪除節點時以遞歸方式更新它。

使用LINQ to Objects,您可以定義一個遞歸擴展方法,該方法返回樹中的所有路徑並獲取最長路徑的長度:

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())));
}

所有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);

(抱歉,沒有可用於驗證的編譯器)

**編輯。 剛看到你有多個根**

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

以下將有效:

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();

如果你應該在DB中使用它,我建議在你的數據庫中添加額外的列來保存樹的深度,有一些深度變化的情況:

  1. 添加新元素,其深度為FatherDepth + 1。
  2. 刪除:如果這是級聯關系,則刪除沒有問題,但如果不是級聯,則應編寫遞歸查詢以更新子級深度。

要查找深度,只需運行查詢以查找最大深度值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM