using System.Collections;
using System.Collections.Generic;
public static void Main()
public static void FirstTest()
var categories = new List<Category>() {
new Category(3, "Shoes", 1),
new Category(5, "Cameras", 4),
new Category(6, "Lenses", 5),
new Category(2, "Balls", 1),
new Category(3, "Shoes", 1),
new Category(0, "Root", -1),
new Category(4, "Electronics", 0),
new Category(8, "Computers", 4),
new Category(1, "Sport", 0),
new Category(9, "Laptops", 8),
new Category(10, "Empty", 0),
new Category(-1, "Broken", 999),
Console.WriteLine("First Example, @Damian Drygiel's answer:");
var tree1 = GenerateTreeWithRecursion<Category, int>(categories, r => r.Id, r => r.ParentId, -1);
PrintTree(tree1.Single());
Console.WriteLine("First Example, @Ilya Ivanov's answer:");
var tree2 = GenerateTreeWithLookup<Category, int>(categories, r => r.Id, r => r.ParentId, -1);
public static void SecondTest()
var a = new Node<string>("a", null);
var a1 = new Node<string>("a1", a);
var a2 = new Node<string>("a2", a);
var b11 = new Node<string>("b11", a1);
var b12 = new Node<string>("b12", a1);
var b21 = new Node<string>("b21", a2);
var b22 = new Node<string>("b22", a2);
var unorderedList = new List<Node<string>>{a2, a1, a, b21, b12, b11, b22};
Console.WriteLine("Second Example, @Damian Drygiel's answer:");
var tree1 = GenerateTreeWithRecursion<Node<string>, string>(unorderedList, r => r.Id, r => r.GetParentId(), a.GetParentId());
PrintTree(tree1.Single());
Console.WriteLine("Second Example, @Ilya Ivanov's answer:");
var tree2 = GenerateTreeWithLookup<Node<string>, string>(unorderedList, r => r.Id, r => r.GetParentId(), a.GetParentId());
public static IEnumerable<TreeItem<T>> GenerateTreeWithRecursion<T, K>(
IEnumerable<T> collection,
Func<T, K> parent_id_selector,
var tree = new List<TreeItem<T>>();
var nodesWithMatchedId = collection.Where(c => EqualityComparer<K>.Default.Equals(parent_id_selector(c), id_to_match)).ToList();
foreach (var c in nodesWithMatchedId)
Children = GenerateTreeWithRecursion(collection, id_selector, parent_id_selector, id_selector(c))
public static TreeItem<T> GenerateTreeWithLookup<T, K>(
IEnumerable<T> collection,
Func<T, K> parent_id_selector,
var tree = collection.Select(r => new TreeItem<T> { Item = r, Children = new List<TreeItem<T>>() }).ToList();
var lookup = tree.ToLookup(node => parent_id_selector(node.Item));
foreach (var node in tree)
node.Children = lookup[id_selector(node.Item)].ToList();
return tree.First(node => EqualityComparer<K>.Default.Equals(parent_id_selector(node.Item), root_id));
static void PrintTree<T>(TreeItem<T> root, int deep = 0)
Console.WriteLine(new String('\t', deep) + root.Item.ToString());
foreach (var c in root.Children)
public T Item { get; set; }
public IEnumerable<TreeItem<T>> Children { get; set; }
public Category(int id, string name, int parentId)
public override string ToString()
#endregion first test class
#region second test class
public T Id { get; set; }
public Node<T> Parent { get; set; }
public Node(T id, Node<T> parent)
public override string ToString()
#endregion second test class