Create a nested list of items from objects with a parent reference
c#, linq
Solution
It is more readable to not use pure Linq for this task, but a mixture of Linq and looping.
Given the following container:
class Node
{
public int Id { get; set; }
public int? ParentId { get; set; }
public List<Node> Children { get; set; }
}
Then you can make the tree with the following code.
var nodes = new List<Node>
{
new Node{ Id = 1 },
new Node{ Id = 2 },
new Node{ Id = 3, ParentId = 1 },
new Node{ Id = 4, ParentId = 1 },
new Node{ Id = 5, ParentId = 3 }
};
foreach (var item in nodes)
{
item.Children = nodes.Where(x => x.ParentId.HasValue && x.ParentId == item.Id).ToList();
}
var tree = nodes.Where(x => !x.ParentId.HasValue).ToList();
This will handle any level of depth and return a proper tree.
Given the following method to print the tree:
private void PrintTree(IEnumerable<Node> nodes, int indent = 0)
{
foreach(var root in nodes)
{
Console.WriteLine(string.Format("{0}{1}", new String('-', indent), root.Id));
PrintTree(root.Children, indent + 1);
}
}
The output of this call is:
1
-3
--5
-4
2
If however you want to use pure Linq for this, you can do the following, however to me it is harder to read:
var tree = nodes.Select(item =>
{
item.Children = nodes.Where(child => child.ParentId.HasValue && child.ParentId == item.Id).ToList();
return item;
})
.Where(item => !item.ParentId.HasValue)
.ToList();
Problem
I am using `C#` and I have a list of items that have a nullable parent ID property. I need to convert this to a list of items that have a list of their children and keep going down generations until there are no items left. My existing class ``` public class Item { public int Id { get; set; } public int? ParentId { get; set; } } ``` My first thoughts... Create a class ``` public class ItemWithChildren { public Item Item { get; set; } public List<ItemWithChildren> Children { get; set; } } ``` Now I need some way to get a `List<ItemWithChildren>` that has all the top level Item objects and their children into the `Children` property. Note that the nesting is not a set number of levels. I was hoping there was an elegant LINQ query that would work. So far I just have this... ``` var itemsWithChildren = items.Select(a => new ItemWithChildren{ Item = a }); ```