0

I have created a simple webapi2 program which returns a json as given below

[
    {
        "MenuId": 1,
        "ParentMenuId": 0
    },
    {
        "MenuId": 2,
        "ParentMenuId": 1
    },
    {
        "MenuId": 3,
        "ParentMenuId": 0
    },
    {
        "MenuId": 4,
        "ParentMenuId": 3
    },
    {
        "MenuId": 5,
        "ParentMenuId": 4
    },
    {
        "MenuId": 6,
        "ParentMenuId": 3
    },
    {
        "MenuId": 7,
        "ParentMenuId": 1
    },
    {
        "MenuId": 8,
        "ParentMenuId": 4
    }
]

The problem is, I need all the child to come under a parent before traversing another parent. The MenuId 6,7 & 8 should come under 8,2 & 5 respectively. That is, I need the order of this json to be exactly like this

[
    {
        "MenuId": 1,
        "ParentMenuId": 0
    },
    {
        "MenuId": 2,
        "ParentMenuId": 1
    },
    {
        "MenuId": 7,
        "ParentMenuId": 1
    },
    {
        "MenuId": 3,
        "ParentMenuId": 0
    },
    {
        "MenuId": 4,
        "ParentMenuId": 3
    },
    {
        "MenuId": 5,
        "ParentMenuId": 4
    },
    {
        "MenuId": 8,
        "ParentMenuId": 4
    },
    {
        "MenuId": 6,
        "ParentMenuId": 3
    }
]

To achieve this, i have coded a spaghetti code in c# as below, it works and gives me the result, but i need to know is there any other better way. Any advice would be helpful. Thank you.

var rolerights = new List<RoleRightsModel>();
var rights = _rightsRepository.GetRights(RoleId);
foreach (var right in rights)
{
    if (right.ParentMenuId == 0)
    {
        rolerights.Add(right);
        var rgs1 = rights.Where(p => p.ParentMenuId == right.MenuId).ToList();
        foreach (var rg1 in rgs1)
        {
            rolerights.Add(rg1);
            var rgs2 = rights.Where(p => p.ParentMenuId == rg1.MenuId).ToList();
            foreach (var rg2 in rgs2)
            {
                rolerights.Add(rg2);
                var rgs3 = rights.Where(p => p.ParentMenuId == rg2.MenuId).ToList();
                foreach (var rg3 in rgs3)
                {
                    rolerights.Add(rg3);
                }
            }
        }
    }
}
//This code works only upto two levels of nesting, if i need three levels, i need to add another loop.
grmbl
  • 2,514
  • 4
  • 29
  • 54
Ranjith Varatharajan
  • 1,596
  • 1
  • 33
  • 76
  • Possible duplicate of [Sorting a list using Lambda/Linq to objects](http://stackoverflow.com/questions/722868/sorting-a-list-using-lambda-linq-to-objects) – Liam Dec 07 '16 at 11:55
  • 2
    Simple, fix the code that produces the json object array? – grmbl Dec 07 '16 at 11:57
  • 1
    Or use Json.Net to create an collection, sort and let Json.Net parse it again as json. – grmbl Dec 07 '16 at 11:58
  • Why is the MenuID 6 at last position? Shouldn't it be coming after MenuID 4 and before MenuID 5? – HGMamaci Dec 07 '16 at 11:59
  • @HGMamaci, MenuId6 is a child of MenuId3 but MenuId5 & 8 are child of MenuId4, so it comes after MenuId8 – Ranjith Varatharajan Dec 07 '16 at 12:02
  • 1
    Prepared a solution for you in answers. This will let you go as deep as you can in your navigation. Hope it helps my friend. – HGMamaci Dec 07 '16 at 12:25

2 Answers2

1

Recursive would help:

using Newtonsoft.Json; /* need to Newtonsoft.Json - NuGet Package */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string menudata = @"[
        {
            ""MenuId"": 1,
            ""ParentMenuId"": 0
        },
        {
            ""MenuId"": 2,
            ""ParentMenuId"": 1
        },
        {
            ""MenuId"": 3,
            ""ParentMenuId"": 0
        },
        {
            ""MenuId"": 4,
            ""ParentMenuId"": 3
        },
        {
            ""MenuId"": 5,
            ""ParentMenuId"": 4
        },
        {
            ""MenuId"": 6,
            ""ParentMenuId"": 3
        },
        {
            ""MenuId"": 7,
            ""ParentMenuId"": 1
        },
        {
            ""MenuId"": 8,
            ""ParentMenuId"": 4
        }
    ]";

            Console.WriteLine(menudata);

            var r = JsonConvert.DeserializeObject<List<Menu>>(menudata);
            r = RecursiveTreeSort(r);
            Console.WriteLine(JsonConvert.SerializeObject(r, Formatting.Indented));
            Console.ReadLine();

        }

        public static List<Menu> RecursiveTreeSort(List<Menu> source, int parentMenuId = 0)
        {
            List<Menu> result = new List<Menu>();
            foreach (var item in source.Where(s => s.ParentMenuId == parentMenuId))
            {
                result.Add(item);
                result.AddRange(RecursiveTreeSort(source, item.MenuId));
            }
            return result;
        }
    }


    public class Menu
    {
        public Menu() { }
        public int MenuId { get; set; }
        public int ParentMenuId { get; set; }
    }

}
HGMamaci
  • 1,339
  • 12
  • 20
0

Using Json.Net (nuGet package):

class Program
    {
        static void Main(string[] args)
        {
            var json = @"[
    {
        ""MenuId"": 1,
        ""ParentMenuId"": 0
    },
    {
        ""MenuId"": 2,
        ""ParentMenuId"": 1
    },
    {
        ""MenuId"": 3,
        ""ParentMenuId"": 0
    },
    {
        ""MenuId"": 4,
        ""ParentMenuId"": 3
    },
    {
        ""MenuId"": 5,
        ""ParentMenuId"": 4
    },
    {
        ""MenuId"": 6,
        ""ParentMenuId"": 3
    },
    {
        ""MenuId"": 7,
        ""ParentMenuId"": 1
    },
    {
        ""MenuId"": 8,
        ""ParentMenuId"": 4
    }
]";

            var collection = JsonConvert.DeserializeObject<IEnumerable<dynamic>>(json);

            // apply sorting here
            var sorted = collection.OrderBy(i => i.ParentMenuId);

            var sortedJson = JsonConvert.SerializeObject(sorted);

        }
    }
grmbl
  • 2,514
  • 4
  • 29
  • 54
  • 2
    If you want compiler safe code you should create an object that holds your json objects properties instead of dynamic. – grmbl Dec 07 '16 at 12:06