C#中父子层次求和

Hierarchical Summation of Parent Child in C#

我有以下型号

   class Entry
{
    public int Id { get; set; }

    public bool IsGroup { get; set; }

    public int? ParentId { get; set; }

    public List<YearCost> YearCost { get; set; } = new List<YearCost>();
}

class YearCost
{
    public int Year { get; set; }
    public decimal Cost { get; set; }
}

我使用上面的模型填充了这个示例列表

    static void Main(string[] args)
    {

        var entries = new List<Entry> {
             new Entry
             {
                 Id = 1,
                 ParentId = null, 
                 IsGroup = true,
             },
             new Entry
             {
                 Id = 2,
                 ParentId = 1,
                 IsGroup = false,
                 YearCost = new List<YearCost> {
                 new YearCost { Year = 2019, Cost = 10 },
                 new YearCost { Year = 2020, Cost = 10 }
                 }
             },
             new Entry
             {
                 Id = 3,
                 ParentId = 1,
                 IsGroup = true
             },
             new Entry
             {
                 Id = 4,
                 ParentId = 3,
                 IsGroup = true
             },
             new Entry
             {
                 Id = 5,
                 ParentId = 4,
                 IsGroup = false,
                 YearCost = new List<YearCost> {
                 new YearCost { Year = 2019, Cost = 15 },
                 new YearCost { Year = 2020, Cost = 10 }
                 }
             },
             new Entry
             {
                 Id = 6,
                 ParentId = 4,
                 IsGroup = false,
                 YearCost = new List<YearCost> {
                 new YearCost { Year = 2019, Cost = 15 },
                 new YearCost { Year = 2020, Cost = 10 }
                 }
             },
             new Entry
             {
                 Id = 7,
                 ParentId = 3,
                 IsGroup = true
             },
             new Entry
             {
                 Id = 8,
                 ParentId = 7,
                 IsGroup = false,
                 YearCost = new List<YearCost> {
                 new YearCost { Year = 2019, Cost = 30 },
                 new YearCost { Year = 2020, Cost = 30 }
                 }
             },
             new Entry
             {
                 Id = 9,
                 ParentId = 7,
                 IsGroup = false,
                 YearCost = new List<YearCost> {
                 new YearCost { Year = 2019, Cost = 20 },
                 new YearCost { Year = 2020, Cost = 20 }
                 }
             },
             new Entry
             {
                 Id = 10,
                 ParentId = 3,
                 IsGroup = false,
                 YearCost = new List<YearCost> {
                 new YearCost { Year = 2019, Cost = 5 },
                 new YearCost { Year = 2020, Cost = 5 }
                 }
             },
        }; 

        Console.WriteLine(String.Format("{0,10}{1,10}{2,10}{3, 10}{4, 10}", "Id", "Group", "Parent Id", 2019, 2020));
        Console.WriteLine(String.Format("{0,10}{1,10}{2,10}{3, 10}{4, 10}", "--", "-----", "---------", "----", "----"));
        foreach (var entry in entries.OrderBy(x=>x.ParentId))
        {
            Console.Write(String.Format("{0,10}{1,10}{2,10}", entry.Id, entry.IsGroup ? "yes" : "no", entry.ParentId?.ToString() ?? "NULL", 2019, 2020));
            foreach (var y in entry.YearCost)
                Console.Write(String.Format("{0,10}", y.Cost));
            Console.WriteLine("\n");
        }
    }

规则 #1:在计算组条目成本时,只有不是组的条目才具有用户手动输入的成本值 规则 #2:允许组嵌套。

我想要的是对每个组做层级求和,如下方括号内的值table所示。

    Id     Group    Parent Id    2019      2020
    --     -----    ---------    ----      ----
     1       yes       NULL      [95]      [85]
     2       no          1        10        10 
     3       yes         1       [85]      [75]
     4       yes         3       [30]      [20]
     7       yes         3       [50]      [50]
    10       no          3         5        5
     5       no          4        15        10
     6       no          4        15        10
     8       no          7        30        30
     9       no          7        20        20

提前致谢

我终于找到了答案

first you need to group element by parent

  var groups = entries.ToLookup(x => x.ParentId).ToDictionary(x => x.Key ?? 0, x 

  => x.ToArray().Select(e => e.Id).ToList());

then get all children helpers

private List<int> GetAllChildren(int? parent, Dictionary<int, List<int>> groups)
    { 
        List<int> children = new List<int>();
        PopulateChildren(parent, children, groups);
        return children;
    }

    private void PopulateChildren(int? parent, List<int> children, Dictionary<int, List<int>> groups)
    {
        List<int> myChildren;
        if (groups.TryGetValue(parent.Value, out myChildren))
        {
            children.AddRange(myChildren);
            foreach (int child in myChildren)
            {
                PopulateChildren(child, children, groups);
            }
        }
    }

Then Iterate over the list to populate the totals

foreach (var item in entries)
{
    if (item.IsGroup)
    {
        var children = GetAllChildren(item.Id, groups);
        children.ForEach(c => {
            var entry = entries.FirstOrDefault(x => x.Id == c);
            if(entry != null)
            {
                if (!item.isGroup)
                {
                    entry.YearCosts?.ForEach(y =>
                    {
                            if (item.YearCosts.FirstOrDefault(yx => yx.Year == y.Year) == null)
                            {
                                item.YearCosts.Add(new YearCost { Year = y.Year, Cost = 0 });
                            }
                            item.YearCosts.FirstOrDefault(yx => yx.Year == y.Year).Cost += y.Cost ?? 0;
                            item.SubTotal += y.Cost ?? 0;
                    });
                }
            } 
        }); 
    }
}