Reputation: 7444
I have a bunch of data that will be represented as a tree. The control that I'm using requires the data to be ordered correctly.
This is the structure of each node:
public class TreeNode
{
public Guid id { get; set; }
public string name { get; set; }
public int level { get; set; }
public Guid? parent { get; set; }
public bool isLeaf { get; set; }
}
I need a way to sort the data so that I have a list of TreeNodes with the root first, followed by its children and so on. In other words all direct children need to follow the parent in the list.
I would also like subnodes and leaf nodes to be sorted by name. (>
= expandable, o
= leaf)
root >
level1a >
level1b >
level2d >
level2a o
level1a o
level1b o
Is there an easy way to do this?
I'm assuming I'll need some recursive function and not wont be able to sort it using a combination of order by statements (something like list.OrderBy(x => x.parent).ThenBy(x => x.level).ThenBy(x => x.isLeaf);
)
Upvotes: 1
Views: 1048
Reputation: 79461
You're correct that doing this with a single LINQ expression is not straightforward. This recursive approach should do the trick:
IEnumerable<TreeNode> TreeOrder(
IEnumerable<TreeNode> nodes)
{
//Find the root node
var root = nodes.Single(node => node.parent == null);
//Build an inverse lookup from parent id to children ids
var childrenLookup = nodes
.Where(node => node.parent != null)
.ToLookup(node => node.parent.Value);
return TreeOrder(root, childrenLookup);
}
IEnumerable<TreeNode> TreeOrder(
TreeNode root,
ILookup<Guid, TreeNode> childrenLookup)
{
yield return root;
if (!childrenLookup.Contains(root.id))
yield break;
foreach (var child in childrenLookup[root.id])
foreach (var node in TreeOrder(child, childrenLookup))
yield return node;
}
Upvotes: 2