如何对LINQ中的所有数字子代属性进行乘法和求和
我有如下对象
public class ResourceTier
{
//primary key. no duplicate
public int Id { get; set; }
public int ParentId { get; set; }
public decimal Volume { get; set; } //has value
public decimal UnitRate { get; set; } //has value
public decimal TotalPrice { get; set; } //has no value
}
TotalPrice
的默认值为0。这是我要填充该值的属性。 TotalPrice
应通过将UnitRate
和Volume
属性相乘,然后将所有子元素(如果有的话)相加来填充。
这是数据
| Id | ParentId | Volume | UnitRate | TotalPrice |
| 1 | 0 | - | - | 180 |
| 2 | 0 | - | - | 30 |
| 3 | 1 | - | - | 130 |
| 4 | 1 | 5 | 10 | 50 |
| 5 | 2 | 3 | 10 | 30 |
| 6 | 3 | - | - | 50 |
| 7 | 3 | 2 | 40 | 80 |
| 8 | 6 | 4 | 10 | 40 |
| 9 | 6 | 1 | 10 | 10 |
当我尝试此操作时,它不起作用。该代码仅包含直接子项的总和,而不是所有子项(大孙子等)
List<ResourceTier> result = ...;
result.ForEach(x => x.TotalPrice =
result.Where(c => c.ParentId == x.Id).Count() == 0 ?
s.UnitRates * s.Volume :
result.Where(c => c.ParentId == x.Id).Select(s => (s.UnitRates * s.Volume)).Sum());
答案 0 :(得分:3)
仅使用Linq的解决方案将很难实现,因为它通常仅尊重一个级别的儿童。为了也获得所有孙子孙的总数,您必须完全走树才能获得孩子(和他们的孩子)的总和。
您必须创建一个使用递归的方法,这意味着它将使用一组不同的参数再次调用自身。这样,您可以先获得所有子节点的总数,然后分配当前节点的值,例如:
private decimal SetTotal(IEnumerable<ResourceTier> tiers, ResourceTier current)
{
current.Total = current.Volume * current.UnitRate;
// Get children of current node
var children = tiers.Where(x => x.ParentId == current.Id && x.Id != current.Id); // The second condition explicitely excludes the current node to avoid infinite loops
foreach(var child in children)
current.Total += SetTotal(tiers, child); // Call method again for children
return current.Total;
}
该函数的第一次调用将使用所有没有父项的项目的ID,例如:
foreach(var topLevelNode in tiers.Where(x => x.ParentId == 0))
SetTotal(tiers, topLevelNode);
请注意,上面的代码应演示递归原理。当然,有更有效的方法可以更快地解决此问题。
答案 1 :(得分:0)
作为其他答案,您需要递归计算总价格:
class MyWebErrorHandler extends yii\web\ErrorHandler {
use handleExceptionMyWay;
}
并使用此方法:
public static decimal total(ResourceTier rt, List<ResourceTier> data)
{
if (data.Where(x=>x.ParentId==rt.Id).Count()==0)
return rt.Volume*rt.UnitRate;
else
{
var sum= data.Where(x => x.ParentId == rt.Id).Select(x=>total( x,data)).Sum();
return rt.UnitRate*rt.Volume+sum;
}
}
输出:
答案 2 :(得分:-1)
LINQ无法更改您的源集合!
但是,您可以创建符合您要求的ResourceTiers
的新集合。之后,您可以决定将其分配给输出,或者决定将其保存在数据库,表等中。
IEnumerable<ResourceTier> sourceCollection = ...
IEnumerable<ResourceTier> resourceTiersWithTotalPrice = sourceCollection
.Select(resourceTier => new ResourceTier
{
Id = resourceTier.Id,
ParentId = resourceTier.ParentId,
...
TotalPrice = resourceTier.Volume * resourceTier.UnitRate,
});