Mapping a flat list to a hierarchical list with parent IDs C#

前端 未结 4 1942
感情败类
感情败类 2020-12-17 19:55

I have a flat list of categories as shown in the following classes

public class FlatCategoryList
{
    public List Categories { get; set;         


        
相关标签:
4条回答
  • 2020-12-17 20:37
    public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList)
    {
        var categories = (from fc in flatCategoryList.Categories
                          select new Category() {
                              ID = fc.ID,
                              Name = fc.Name,
                              ParentID = fc.ParentID
                          }).ToList();
    
        var lookup = categories.ToLookup(c => c.ParentID);
    
        foreach(var c in categories)
        {
            // you can skip the check if you want an empty list instead of null
            // when there is no children
            if(lookup.Contains(c.ID))
                c.ChildCategories = lookup[c.ID].ToList();
        }
    
        return new HieraricalCategoryList() { Categories = categories };
    }
    
    0 讨论(0)
  • 2020-12-17 20:40

    A very easy and highly performant way to make this transformation is to create a lookup in which you map ID values to the nodes that should be the children of that ID value. This lookup can be created in a single pass of the nodes. After that you can iterate through all of the nodes again assigning their child collection to be the value of their ID value in the lookup.

    Note that this is simpler if the lookup maps to objects of the type you are converting to, not converting from.

    var lookup = list.Categories
        .Select(category => new Category()
        {
            ID = category.ID,
            Name = category.Name,
            ParentID = category.ParentID,
        })
        .ToLookup(category => category.ParentID);
    
    foreach (var category in lookup.SelectMany(x => x))
        category.ChildCategories = lookup[category.ID].ToList();
    
    var newList = new HieraricalCategoryList()
    {
        Categories = lookup[null].ToList(),
    };
    
    0 讨论(0)
  • 2020-12-17 20:50

    Improved the suggested answer

    public HieraricalCategoryList MapCategories(FlatCategoryList flatCategoryList)
    {
        var categories = (from fc in flatCategoryList.Categories
                          select new Category() {
                              ID = fc.ID,
                              Name = fc.Name,
                              ParentID = fc.ParentID
                          }).ToList();
    
        var lookup = categories.ToLookup(c => c.ParentID);
    
        foreach(var c in rootCategories)//only loop through root categories
        {
            // you can skip the check if you want an empty list instead of null
            // when there is no children
            if(lookup.Contains(c.ID))
                c.ChildCategories = lookup[c.ID].ToList();
        }
    
        //if you want to return only root categories not all the flat list
        //with mapped child 
    
        categories.RemoveAll(c => c.ParentId != 0);//put what ever your parent id is
    
        return new HieraricalCategoryList() { Categories = categories };
    }
    
    0 讨论(0)
  • 2020-12-17 20:50

    Use a two-pass solution. This assumes the full collection can fit in memory. The first pass scans the list of flat categories, and builds a dictionary of Category, indexed by the ID. The child collections are all empty at this point, and the parent property is null. Then the second pass scans them again, and builds up the child collections and sets the parent property.

    Untested code:

    var final = new Dictionary<string, Category>();
    var rootCategories = new List<Category>();
    
    // Pass 1
    foreach (var flat in flatList)
    {
      Category cat = new Category() { ID = flat.ID, Name = flat.Name, parent = null }
      cat.Children = new List<Category>();
      final[flat.ID] = cat;
    }
    
    // Pass 2
    foreach (var flat in flatList)
    {
      // find myself -- must exist
      var self = final[flat.ID];
    
      // find parent -- may not exist
      if (final.ContainsKey(flat.ParentID)
      {
        var parent = final[flat.ParentID];
        parent.Children.Add(self);
        self.Parent = parent;     
      }
      else
      {
        rootCategories.Add(self);
      }
    
    }
    

    This will have O(n) running time, since it's two linear scans, with some dictionary lookups, which are O(1).

    0 讨论(0)
提交回复
热议问题