Home > Software design >  Group the similar items in a multiple level hierarchy
Group the similar items in a multiple level hierarchy

Time:04-29

I have a list of categories with duplicate key values AppCategoryId. I wanted to create a 3 level hierarchy with that.

Data are in this way:

var appCategoryList = new List<AppCategoryDataModel>() {
    new AppCategoryDataModel() { AppCategoryId = 4844, ParentappCategoryId = null , AppCategoryName = "ItemResearch", ProtocolId = 5164, ProtocolTitle="ABC: Evaluation" },
    new AppCategoryDataModel() { AppCategoryId = 4844, ParentappCategoryId = null, AppCategoryName = "ItemResearch", ProtocolId = null, ProtocolTitle=""},
    new AppCategoryDataModel() { AppCategoryId = 4845, ParentappCategoryId = null, AppCategoryName = "ItemHostpital", ProtocolId = null, ProtocolTitle="" },
    new AppCategoryDataModel() { AppCategoryId = 4845, ParentappCategoryId = null, AppCategoryName = "ItemHostpital", ProtocolId =5162 , ProtocolTitle="ABC: 3/28/20" },
    new AppCategoryDataModel() { AppCategoryId = 4845, ParentappCategoryId = null, AppCategoryName = "ItemHostpital", ProtocolId =5164 , ProtocolTitle="ABC: Evaluation" },
    new AppCategoryDataModel() { AppCategoryId = 4845, ParentappCategoryId = null, AppCategoryName = "ItemHostpital", ProtocolId =5165 , ProtocolTitle="ABC: section", },
    new AppCategoryDataModel() { AppCategoryId = 4845, ParentappCategoryId = null, AppCategoryName = "ItemHostpital", ProtocolId =5192 , ProtocolTitle="ABC: 3/31/20", },
    new AppCategoryDataModel() { AppCategoryId = 4846, ParentappCategoryId = null, AppCategoryName = "Contact information", ProtocolId = null, ProtocolTitle="", },
    new AppCategoryDataModel() { AppCategoryId = 4846, ParentappCategoryId = null, AppCategoryName = "Contact information", ProtocolId =5164 , ProtocolTitle="ABC: Evaluation", },
    new AppCategoryDataModel() { AppCategoryId = 4852, ParentappCategoryId = null, AppCategoryName = "UP", ProtocolId =null , ProtocolTitle="", },
    new AppCategoryDataModel() { AppCategoryId = 4852, ParentappCategoryId = null, AppCategoryName = "UP", ProtocolId = 5164, ProtocolTitle="ABC: Evaluation", },
    new AppCategoryDataModel() { AppCategoryId = 4853, ParentappCategoryId = null, AppCategoryName = "Hospitalist", ProtocolId = null, ProtocolTitle="", },
    new AppCategoryDataModel() { AppCategoryId = 4853, ParentappCategoryId = null, AppCategoryName = "Hospitalist", ProtocolId = 5164, ProtocolTitle="ABC: Evaluation" },
    new AppCategoryDataModel() { AppCategoryId = 4854, ParentappCategoryId = null, AppCategoryName = "COP", ProtocolId =null , ProtocolTitle=""},
    new AppCategoryDataModel() { AppCategoryId = 4854, ParentappCategoryId = null, AppCategoryName = "COP", ProtocolId = 5162, ProtocolTitle="ABC: 3/28/20"},
    new AppCategoryDataModel() { AppCategoryId = 4854, ParentappCategoryId = null, AppCategoryName = "COP", ProtocolId = 5164, ProtocolTitle="ABC: Evaluation" },
    new AppCategoryDataModel() { AppCategoryId = 5023, ParentappCategoryId = null, AppCategoryName = "Call survival guide", ProtocolId = null, ProtocolTitle="" },
    new AppCategoryDataModel() { AppCategoryId = 5023, ParentappCategoryId = null, AppCategoryName = "Call survival guides", ProtocolId =5164 , ProtocolTitle="ABC: Evaluation" },
    new AppCategoryDataModel() { AppCategoryId = 5085, ParentappCategoryId = null, AppCategoryName = "OE", ProtocolId =null, ProtocolTitle="" },
    new AppCategoryDataModel() { AppCategoryId = 5085, ParentappCategoryId = null, AppCategoryName = "OE", ProtocolId =5164 , ProtocolTitle="ABC: Evaluation" },
    new AppCategoryDataModel() { AppCategoryId = 5334, ParentappCategoryId = 5085, AppCategoryName = "mmkk update", ProtocolId =null , ProtocolTitle= null },
    new AppCategoryDataModel() { AppCategoryId = 5336, ParentappCategoryId = 5085, AppCategoryName = "xdgdrg", ProtocolId =null , ProtocolTitle=null },
    new AppCategoryDataModel() { AppCategoryId = 5348, ParentappCategoryId = 5023, AppCategoryName = "test", ProtocolId =null , ProtocolTitle=null },
    new AppCategoryDataModel() { AppCategoryId = 5341, ParentappCategoryId = 5023, AppCategoryName = "New Category Level-1", ProtocolId =null , ProtocolTitle= null },
    new AppCategoryDataModel() { AppCategoryId = 5349, ParentappCategoryId = 5341, AppCategoryName = "New Category Level-2", ProtocolId =null , ProtocolTitle= null },
    new AppCategoryDataModel() { AppCategoryId = 5352, ParentappCategoryId = 5348, AppCategoryName = "New category3", ProtocolId =null , ProtocolTitle= null },

}.OrderBy(ap => ap.AppCategoryName);

AppCategoryDataModel

public class AppCategoryDataModel
{
    public int AppCategoryId { get; set; }
    public int? ParentappCategoryId { get; set; }
    public string AppCategoryName { get; set; }
    public int? ProtocolId { get; set; }
    public string ProtocolTitle { get; set; }
}

Converted the list to lookup:

var lookup = appCategoryList.ToLookup(app => app.AppCategoryId);

Iterated through the list:

var listofCategory = new List<FirstLevelCategory>();

foreach (var item in appCategoryList)
{
    var firstLevelCategory = new FirstLevelCategory();

    if (!item.ParentappCategoryId.HasValue)
    {
        firstLevelCategory.AppCategoryId = item.AppCategoryId;
        firstLevelCategory.AppCategoryName = item.AppCategoryName;

        firstLevelCategory.AppCategoryProtocolData = new List<ProtocolDetails>();
        var protocolDetails = new ProtocolDetails();

        foreach (AppCategoryDataModel appCategory in lookup[item.AppCategoryId])
        {
            if (appCategory.ProtocolId.HasValue)
            {
                protocolDetails.ProtocolId = appCategory.ProtocolId.Value;
                protocolDetails.ProtocolTitle = appCategory.ProtocolTitle;
            }
            firstLevelCategory.AppCategoryProtocolData.Add(protocolDetails);
        }
        continue;
    }

    else
    {

    }

    listofCategory.Add(firstLevelCategory);
}

In the foreach when 'appCategoryList' is iterated first it works fine. But in the next loop due to the repetition of the same appcategoryid there will be a duplicate addition of the same data as much as time the appcateogory id is present.

After all the data has been added I could remove them at the end but it will be another task, what could be done to avoid the addition of the duplicate first?

Alternatively, I tried this way But in this way, only the last item will be added to the list.

foreach (var item in lookup)
{
    var firstLevelCategory = new FirstLevelCategory();

    List<AppCategoryDataModel> categoryList = item.ToList();            foreach (var item in lookup)
{
    var firstLevelCategory = new FirstLevelCategory();

    List<AppCategoryDataModel> categoryList = item.ToList();

    foreach (AppCategoryDataModel appCategory in categoryList)
    {
        if (!appCategory.ParentappCategoryId.HasValue)
        {
            firstLevelCategory.AppCategoryId = appCategory.AppCategoryId;
            firstLevelCategory.AppCategoryName = appCategory.AppCategoryName;
            firstLevelCategory.AppCategoryProtocolData = new List<ProtocolDetails>();
            var protocolDetails = new ProtocolDetails();
            if (appCategory.ProtocolId.HasValue)
            {
                protocolDetails.ProtocolId = appCategory.ProtocolId.Value;
                protocolDetails.ProtocolTitle = appCategory.ProtocolTitle;
            }
            firstLevelCategory.AppCategoryProtocolData.Add(protocolDetails);
        }
        else
        {

        }
    }
    listofCategory.Add(firstLevelCategory);
}

I how can I add the item to the list effectively with a much cheaper approach?

public class FirstLevelCategory
{
    public int AppCategoryId { get; set; }
    public string AppCategoryName { get; set; }
    public List<SecondLevelCategory> SubCategory { get; set; }
    public List<ProtocolDetails> AppCategoryProtocolData { get; set; }
}
public class ProtocolDetails
{
    public int ProtocolId { get; set; }
    public string ProtocolTitle { get; set; }
}

SecondLevelCategory

public class SecondLevelCategory
{
    public int AppCategoryId { get; set; }
    public string AppCategoryName { get; set; }
 
    public IEnumerable<ProtocolDetails> SubCategoryProtocolData { get; set; }
    public List<ThirdLevelCategory> ThirdLevelCategory { get; set; }
}

ThirdLevelCategory

 public class ThirdLevelCategory
 {
    public int AppCategoryId { get; set; }
    public string AppCategoryName { get; set; }
    public IEnumerable<ProtocolDetails> ThirdLevelCategoryProtocolData { get; set; }
 }

Expected Output are something similar (output for the first category only)

ItemResearch
    ABC: Evaluation
ItemHostpital
    ABC: 3/28/20
    ABC: Evaluation
    ABC: section
    ABC: 3/31/20
Contact information
    ABC: Evaluation
UP
    ABC: Evaluation

Edit: More data are added that have parentscategoryid, and class for first, second and third level are added.

CodePudding user response:

Using dictionaries makes your life easier:

        Dictionary<int, FirstLevelCategory> dictCategories = new Dictionary<int, FirstLevelCategory>();
        foreach (AppCategoryDataModel category in appCategoryList) 
        {
            if (!dictCategories.ContainsKey(category.AppCategoryId))
            {
                dictCategories.Add(category.AppCategoryId, new FirstLevelCategory()
                {
                    AppCategoryId = category.AppCategoryId,
                    AppCategoryName = category.AppCategoryName,
                    AppCategoryProtocolData = category.ProtocolId != null ? new List<ProtocolDetails>() { new ProtocolDetails() {
                        ProtocolId = (int)category.ProtocolId,
                        ProtocolTitle = category.ProtocolTitle
                    } } : new List<ProtocolDetails>()
                });
            }
            else 
            {
                if (category.ProtocolId != null)
                dictCategories[category.AppCategoryId].AppCategoryProtocolData.Add(new ProtocolDetails()
                {
                    ProtocolId = (int)category.ProtocolId,
                    ProtocolTitle = category.ProtocolTitle
                });
            }
        }
        var test = dictCategories.Values.ToList();

I didn't check for duplicates in protocol, as for yours code seems there is no need but if it's needed you can do it the same way

  •  Tags:  
  • c#
  • Related