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;
});
}
}
});
}
}
我有以下型号
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;
});
}
}
});
}
}