Reputation: 99
I have the following class
public class TreeNode
{
public string Id { get; set; }
public int Data { get; set; }
public List<TreeNode> Children { get; private set; }
public TreeNode(string node, int data)
{
Id = node;
Data = data;
Children = new List<TreeNode>();
}
public TreeNode(string node, params TreeNode[] children)
{
Id = node;
Children = new List<TreeNode>(children);
}
public override string ToString()
{
return Id;
}
}
It's n-ary tree in which only the leaf nodes(nodes with no children) will have the data property populated. I want to convert this nested list into multilevel dictionary using LINQ. For example if the tree is as below
TreeNode rootNode =
new TreeNode("node-0",
new TreeNode("node-1",
new TreeNode("node-2", 20)),
new TreeNode("node-3", 19),
new TreeNode("node-4",
new TreeNode("node-5", 25),
new TreeNode("node-6", 40)));
I want the above structure to be converted to Dictionary (note: Not flat Dictionary) as below using LINQ. I need the root dictionary as the result of LINQ. How do i get it done. Kindly help me.
Dictionary<string, object> d4 = new Dictionary<string, object>();
d4.Add("node-5", 25);
d4.Add("node-6", 40);
Dictionary<string, object> d3 = new Dictionary<string, object>();
d3.Add("node-4", d4);
Dictionary<string, object> d2 = new Dictionary<string, object>();
d2.Add("node-2", 20);
Dictionary<string, object> d1 = new Dictionary<string, object>();
d1.Add("node-1", d2);
d1.Add("node-3", 19);
d1.Add("node-4", d4);
Dictionary<string, object> root = new Dictionary<string, object>();
root.Add("node-0", d1);
Upvotes: 1
Views: 999
Reputation: 16956
Update :
Since question is not about flattening hierarchy, and user is looking for hierarchical Dictionary
for a given an input, I've modified code a bit.
public static void Main()
{
var rootNode =
new TreeNode("node-0",
new TreeNode("node-1",
new TreeNode("node-2", 20)),
new TreeNode("node-3", 19),
new TreeNode("node-4",
new TreeNode("node-5", 25),
new TreeNode("node-6", 40)));
var result = ReadHierarchy(new List<TreeNode> {rootNode});
foreach (var r in result)
{
Console.WriteLine("{0} - {1}", r.Key, r.Value);
}
Console.ReadKey();
}
private static Dictionary<string, object> ReadHierarchy(IEnumerable<TreeNode> collection)
{
return collection.ToDictionary(node => node.Id,
node => node.Children.Count > 0 ? ReadHierarchy(node.Children) : node.Data as object);
}
Working fiddler example
Below solution flattens hierarchy(Use if required).
Here is simple recursive method which takes List
as an input and returns flattened collection..
static List<TreeNode> ReadHierarchy(List<TreeNode> collection)
{
return collection.SelectMany(c => ReadHierarchy(c.Children)).Concat(collection).ToList();
}
You can use simple Linq
statement to convert returned list to Dictionary
.
TreeNode rootNode =
new TreeNode("node-0",
new TreeNode("node-1",
new TreeNode("node-2", 20)),
new TreeNode("node-3", 19),
new TreeNode("node-4",
new TreeNode("node-5", 25),
new TreeNode("node-6", 40)));
var result = ReadHierarchy(new List<TreeNode> {rootNode}).ToDictionary(c=>c.Id, c=>c);
Working Fiddler example
Upvotes: 1
Reputation: 12544
Perhaps it would be better to implement the getvalue logic in the treenode itself, but otherwise using recursion, the following should do the trick:
Func<TreeNode, object> getvalue = null;
getvalue = tn => tn.Children.Count == 0 ? (object)tn.Data : tn.Children.ToDictionary(n => n.Id, getvalue);
var result = getvalue(rootNode) as Dictionary<string, object>;
NB, this assumes the root always contains children, otherwise getvalue would return the 'data' of the root node.
Upvotes: 1