I have a list of hierarchical data like this:
var list = new List<Data>(){some data...}
class Data
{
public int number;
public List<Data> info;
}
Note: Data in leaf of tree --> info = null
Example:
numbers are number property
of Data class
--1
--11
--2
--21
--22
--23
--24
--3
--31
--32
--321
--322
--4
--41
--42
How to know max depth of tree with linq query(Not Recursive method or for loop ) to list of data?
in this example max level is 3 for 321,322
Thanks.
LINQ and SQL operate on flat data structures; they are not designed for recursive data structures.
With LINQ to Entities, I believe you're out of luck. Store the depth of the subtree in each node and recursively update it whenever you insert/delete a node.
With LINQ to Objects, you could define a recursive extension method that returns all paths in a tree and take the length of the longest path:
var result = root.Paths().Max(path => path.Length);
where
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())));
}
All Linq operators use a loop in some way so it is not possible to solve with linq if the requirement is no loop.
It is possible without recursion. You just need a stack. Something like
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;
}
}
Your linq query will then be
FlattenWithDepth(root, x => x.info ?? Enumerable.Empty<Data>()).Max(x => x.Item1);
(sorry don't have a compiler available to verify)
** Edit. Just saw that you had multiple roots **
list.SelectMany(y => FlattenWithDepth(y, x => x.info ?? Enumerable.Empty<Data>()))
.Max(x => x.Item1)
The following would work:
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;
}
}
Then just call:
var maxDepth = list.MaxDepthOfTree();
If you should use it in DB, I would suggest add additional column to your DB to save the depth of tree, there are some situation which depth changes:
For finding depth just run a query to find the maximum depth value.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.