using System;
using System.Collections .Generic ;
using System.Linq ;
public class Test
{
public static void Main( )
{
var samples = new[ ] {
new Category { Id = 1 , ParentCategoryId = 8 , SortOrder = 1 , Text = "Firefall" } ,
new Category { Id = 2 , ParentCategoryId = 8 , SortOrder = 2 , Text = "Left 4 Dead 2" } ,
new Category { Id = 3 , ParentCategoryId = 8 , SortOrder = 3 , Text = "Renegade X" } ,
new Category { Id = 4 , ParentCategoryId = 2 , SortOrder = 2 , Text = "Survival" } ,
new Category { Id = 5 , ParentCategoryId = 0 , SortOrder = 1 , Text = "General" } ,
new Category { Id = 6 , ParentCategoryId = 8 , SortOrder = 4 , Text = "Battlefield 4" } ,
new Category { Id = 7 , ParentCategoryId = 2 , SortOrder = 1 , Text = "Versus" } ,
new Category { Id = 8 , ParentCategoryId = 0 , SortOrder = 2 , Text = "Games" } ,
new Category { Id = 9 , ParentCategoryId = 0 , SortOrder = 3 , Text = "Army Restricted Area" } ,
new Category { Id = 10 , ParentCategoryId = 9 , SortOrder = 1 , Text = "Kool Kids Klub" }
} ;
var categories = new List< Category> ( samples) ;
// hierarchycal
var categoryTree = CategoryTree.Create ( categories, o => o.ParentCategoryId == 0 ) ;
// recursively called Console.WriteLine on every node
PrintNodes( categoryTree) ;
Console.WriteLine ( new string( '-' , 80 ) ) ;
var flatTree = categoryTree.Flatten ( ) ;
foreach( var category in flatTree) {
Console.WriteLine ( category.DisplayText ) ;
}
}
public static void PrintNodes( CategoryTree tree) {
if ( tree == null || ! tree.Any ( ) ) return ;
foreach( var node in tree) {
Console.WriteLine ( node.DisplayText ) ;
PrintNodes( node.Children ) ;
}
}
}
public class Category {
public int Id { get; set; }
public int ParentCategoryId { get; set; }
public int SortOrder { get; set; }
public string Text { get; set; }
}
public class CategoryNode : Category {
public CategoryNode( Category category) {
Id = category.Id ;
ParentCategoryId = category.ParentCategoryId ;
SortOrder = category.SortOrder ;
Text = category.Text ;
}
public CategoryTree Children { get; set; }
public int Level { get; set; }
public string DisplayText {
get {
return string.Concat ( new string( '.' , Level* 2 ) , Text) ;
}
}
}
public class CategoryTree : IEnumerable< CategoryNode> {
private List< CategoryNode> innerList = new List< CategoryNode> ( ) ;
public CategoryTree( IEnumerable< CategoryNode> nodes) {
innerList = new List< CategoryNode> ( nodes) ;
}
public IEnumerator< CategoryNode> GetEnumerator( )
{
return innerList.GetEnumerator ( ) ;
}
System.Collections .IEnumerator System.Collections .IEnumerable .GetEnumerator ( )
{
return this.GetEnumerator ( ) ;
}
public IEnumerable< CategoryNode> Flatten( ) {
foreach( var category in innerList.OrderBy ( o => o.SortOrder ) ) {
yield return category;
if ( category.Children != null ) {
foreach( var child in category.Children .Flatten ( ) ) {
yield return child;
}
}
}
}
public static CategoryTree Create( IEnumerable< Category> categories, Func< Category, bool> parentPredicate, int level = 0 ) {
var nodes = categories
.Where ( parentPredicate)
.OrderBy ( o => o.SortOrder )
.Select ( item =>
new CategoryNode( item) {
Level = level,
Children = Create( categories, o => o.ParentCategoryId == item.Id , level + 1 )
} ) ;
return new CategoryTree( nodes) ;
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLkxpbnE7CgpwdWJsaWMgY2xhc3MgVGVzdAp7CglwdWJsaWMgc3RhdGljIHZvaWQgTWFpbigpCgl7CgkJdmFyIHNhbXBsZXMgPSBuZXdbXSB7CgkJCW5ldyBDYXRlZ29yeSB7IElkID0gMSwgUGFyZW50Q2F0ZWdvcnlJZCA9IDgsIFNvcnRPcmRlciA9IDEsIFRleHQgPSAiRmlyZWZhbGwiIH0sCgkJCW5ldyBDYXRlZ29yeSB7IElkID0gMiwgUGFyZW50Q2F0ZWdvcnlJZCA9IDgsIFNvcnRPcmRlciA9IDIsIFRleHQgPSAiTGVmdCA0IERlYWQgMiIgfSwKCQkJbmV3IENhdGVnb3J5IHsgSWQgPSAzLCBQYXJlbnRDYXRlZ29yeUlkID0gOCwgU29ydE9yZGVyID0gMywgVGV4dCA9ICJSZW5lZ2FkZSBYIiB9LAoJCQluZXcgQ2F0ZWdvcnkgeyBJZCA9IDQsIFBhcmVudENhdGVnb3J5SWQgPSAyLCBTb3J0T3JkZXIgPSAyLCBUZXh0ID0gIlN1cnZpdmFsIiB9LAoJCQluZXcgQ2F0ZWdvcnkgeyBJZCA9IDUsIFBhcmVudENhdGVnb3J5SWQgPSAwLCBTb3J0T3JkZXIgPSAxLCBUZXh0ID0gIkdlbmVyYWwiIH0sCgkJCW5ldyBDYXRlZ29yeSB7IElkID0gNiwgUGFyZW50Q2F0ZWdvcnlJZCA9IDgsIFNvcnRPcmRlciA9IDQsIFRleHQgPSAiQmF0dGxlZmllbGQgNCIgfSwKCQkJbmV3IENhdGVnb3J5IHsgSWQgPSA3LCBQYXJlbnRDYXRlZ29yeUlkID0gMiwgU29ydE9yZGVyID0gMSwgVGV4dCA9ICJWZXJzdXMiIH0sCgkJCW5ldyBDYXRlZ29yeSB7IElkID0gOCwgUGFyZW50Q2F0ZWdvcnlJZCA9IDAsIFNvcnRPcmRlciA9IDIsIFRleHQgPSAiR2FtZXMiIH0sCgkJCW5ldyBDYXRlZ29yeSB7IElkID0gOSwgUGFyZW50Q2F0ZWdvcnlJZCA9IDAsIFNvcnRPcmRlciA9IDMsIFRleHQgPSAiQXJteSBSZXN0cmljdGVkIEFyZWEiIH0sCgkJCW5ldyBDYXRlZ29yeSB7IElkID0gMTAsIFBhcmVudENhdGVnb3J5SWQgPSA5LCBTb3J0T3JkZXIgPSAxLCBUZXh0ID0gIktvb2wgS2lkcyBLbHViIiB9CgkJfTsKCQkKCQl2YXIgY2F0ZWdvcmllcyA9IG5ldyBMaXN0PENhdGVnb3J5PihzYW1wbGVzKTsKCQkKCQkvLyBoaWVyYXJjaHljYWwKCQl2YXIgY2F0ZWdvcnlUcmVlID0gQ2F0ZWdvcnlUcmVlLkNyZWF0ZShjYXRlZ29yaWVzLCBvID0+IG8uUGFyZW50Q2F0ZWdvcnlJZCA9PSAwKTsKCQkvLyByZWN1cnNpdmVseSBjYWxsZWQgQ29uc29sZS5Xcml0ZUxpbmUgb24gZXZlcnkgbm9kZQoJCVByaW50Tm9kZXMoY2F0ZWdvcnlUcmVlKTsKCQkKCQlDb25zb2xlLldyaXRlTGluZShuZXcgc3RyaW5nKCctJyw4MCkpOwoJCQoJCXZhciBmbGF0VHJlZSA9IGNhdGVnb3J5VHJlZS5GbGF0dGVuKCk7CgkJZm9yZWFjaCh2YXIgY2F0ZWdvcnkgaW4gZmxhdFRyZWUpIHsKCQkJQ29uc29sZS5Xcml0ZUxpbmUoY2F0ZWdvcnkuRGlzcGxheVRleHQpOwoJCX0KCX0KCQoJcHVibGljIHN0YXRpYyB2b2lkIFByaW50Tm9kZXMoQ2F0ZWdvcnlUcmVlIHRyZWUpIHsKCQlpZiAodHJlZSA9PSBudWxsIHx8ICF0cmVlLkFueSgpKSByZXR1cm47CgkJCgkJZm9yZWFjaCh2YXIgbm9kZSBpbiB0cmVlKSB7CgkJCUNvbnNvbGUuV3JpdGVMaW5lKG5vZGUuRGlzcGxheVRleHQpOwoJCQlQcmludE5vZGVzKG5vZGUuQ2hpbGRyZW4pOwoJCX0KCX0KfQoKcHVibGljIGNsYXNzIENhdGVnb3J5IHsKCXB1YmxpYyBpbnQgSWQgeyBnZXQ7IHNldDsgfQoJcHVibGljIGludCBQYXJlbnRDYXRlZ29yeUlkIHsgZ2V0OyBzZXQ7IH0KCXB1YmxpYyBpbnQgU29ydE9yZGVyIHsgZ2V0OyBzZXQ7IH0KCXB1YmxpYyBzdHJpbmcgVGV4dCB7IGdldDsgc2V0OyB9Cn0KCnB1YmxpYyBjbGFzcyBDYXRlZ29yeU5vZGUgOiBDYXRlZ29yeSB7CiAgcHVibGljIENhdGVnb3J5Tm9kZShDYXRlZ29yeSBjYXRlZ29yeSkgewogIAlJZCA9IGNhdGVnb3J5LklkOwoJUGFyZW50Q2F0ZWdvcnlJZCA9IGNhdGVnb3J5LlBhcmVudENhdGVnb3J5SWQ7CglTb3J0T3JkZXIgPSBjYXRlZ29yeS5Tb3J0T3JkZXI7CglUZXh0ID0gY2F0ZWdvcnkuVGV4dDsKICB9CiAgIAogIHB1YmxpYyBDYXRlZ29yeVRyZWUgQ2hpbGRyZW4geyBnZXQ7IHNldDsgfQogIHB1YmxpYyBpbnQgTGV2ZWwgeyBnZXQ7IHNldDt9CiAgcHVibGljIHN0cmluZyBEaXNwbGF5VGV4dCB7IAogICAJZ2V0IHsKICAgCSAgcmV0dXJuIHN0cmluZy5Db25jYXQobmV3IHN0cmluZygnLicsIExldmVsKjIpLCBUZXh0KTsJCiAJfQogIH0KfQoKcHVibGljIGNsYXNzIENhdGVnb3J5VHJlZSA6IElFbnVtZXJhYmxlPENhdGVnb3J5Tm9kZT4gewoJcHJpdmF0ZSBMaXN0PENhdGVnb3J5Tm9kZT4gaW5uZXJMaXN0ID0gbmV3IExpc3Q8Q2F0ZWdvcnlOb2RlPigpOwoJCglwdWJsaWMgQ2F0ZWdvcnlUcmVlKElFbnVtZXJhYmxlPENhdGVnb3J5Tm9kZT4gbm9kZXMpIHsKCQlpbm5lckxpc3QgPSBuZXcgTGlzdDxDYXRlZ29yeU5vZGU+KG5vZGVzKTsJCgl9CgkKCXB1YmxpYyBJRW51bWVyYXRvcjxDYXRlZ29yeU5vZGU+IEdldEVudW1lcmF0b3IoKQogICAgewogICAgICAgIHJldHVybiBpbm5lckxpc3QuR2V0RW51bWVyYXRvcigpOwogICAgfQoKICAgIFN5c3RlbS5Db2xsZWN0aW9ucy5JRW51bWVyYXRvciBTeXN0ZW0uQ29sbGVjdGlvbnMuSUVudW1lcmFibGUuR2V0RW51bWVyYXRvcigpCiAgICB7CiAgICAgICAgcmV0dXJuIHRoaXMuR2V0RW51bWVyYXRvcigpOwogICAgfQogICAgCglwdWJsaWMgSUVudW1lcmFibGU8Q2F0ZWdvcnlOb2RlPiBGbGF0dGVuKCkgewoJICBmb3JlYWNoKHZhciBjYXRlZ29yeSBpbiBpbm5lckxpc3QuT3JkZXJCeShvID0+IG8uU29ydE9yZGVyKSkgewoJICAJeWllbGQgcmV0dXJuIGNhdGVnb3J5OwoJICAJaWYgKGNhdGVnb3J5LkNoaWxkcmVuICE9IG51bGwpIHsKCSAgCSAgZm9yZWFjaCh2YXIgY2hpbGQgaW4gY2F0ZWdvcnkuQ2hpbGRyZW4uRmxhdHRlbigpKSB7CgkgIAkJICB5aWVsZCByZXR1cm4gY2hpbGQ7CgkgIAkgIH0KCSAgCX0KCSAgfQogICB9CiAgIAogICBwdWJsaWMgc3RhdGljIENhdGVnb3J5VHJlZSBDcmVhdGUoSUVudW1lcmFibGU8Q2F0ZWdvcnk+IGNhdGVnb3JpZXMsIEZ1bmM8Q2F0ZWdvcnksIGJvb2w+IHBhcmVudFByZWRpY2F0ZSwgaW50IGxldmVsID0gMCkgewoJCXZhciBub2RlcyA9IGNhdGVnb3JpZXMKCQkJLldoZXJlKHBhcmVudFByZWRpY2F0ZSkKCQkJLk9yZGVyQnkobyA9PiBvLlNvcnRPcmRlcikKCQkJLlNlbGVjdChpdGVtID0+IAoJCQkJbmV3IENhdGVnb3J5Tm9kZShpdGVtKSB7IAoJCQkJCUxldmVsID0gbGV2ZWwsCgkJCQkJQ2hpbGRyZW4gPSBDcmVhdGUoY2F0ZWdvcmllcywgbyA9PiBvLlBhcmVudENhdGVnb3J5SWQgPT0gaXRlbS5JZCwgbGV2ZWwgKyAxKQoJCQkJfSk7CgkJCQkKCQlyZXR1cm4gbmV3IENhdGVnb3J5VHJlZShub2Rlcyk7Cgl9Cn0=