return new SchoolFees(
new Percentage(schoolFeesResult.Sum(x => (x.Amount.Value / totalFees) * x.TuitionFee.Value)),
new Percentage(schoolFeesResult.Sum(x => (x.Amount.Value / totalFees) * x.TravellingFee.Value)),
new Percentage(schoolFeesResult.Sum(x => (x.Amount.Value / totalFees) * x.ResidentialFee.Value)));
我是否可以通过schoolFeesResult
操作一次来计算每种不同类型费用的加权平均值(Tuition
,Travelling
,Residence
)。基本上我不希望(x.Amount.Value / totalFees)
在我的代码中出现3次?
答案 0 :(得分:3)
您可以使用以下内容:
var fees = from fee in schoolFeesResult
let weight = fee.Amount.Value / totalFees
select new
{
TuitionFee = weight * fee.TuitionFee.Value,
TravellingFee = weight * fee.TravellingFee.Value,
ResidentialFee = weight * fee.ResidentialFee.Value
};
// if the calculation of the fees is a performance bottleneck,
// uncomment the next line:
// fees = fees.ToList();
return new SchoolFees(
new Percentage(fees.Sum(x => x.TuitionFee),
new Percentage(fees.Sum(x => x.TravellingFee),
new Percentage(fees.Sum(x => x.ResidentialFee));
你可以走得更远:
var fees = (from fee in schoolFeesResult
let weight = fee.Amount.Value / totalFees
group fee by 1 into g
select new
{
TuitionFee = g.Sum(x => weight * x.TuitionFee.Value),
TravellingFee = g.Sum(x => weight * x.TravellingFee.Value),
ResidentialFee = g.Sum(x => weight * x.ResidentialFee.Value)
}).Single();
return new SchoolFees(
new Percentage(fees.TuitionFee,
new Percentage(fees.TravellingFee,
new Percentage(fees.ResidentialFee);
但我怀疑第二个版本是个好主意。它使代码难以理解。我纯粹出于学术原因添加它,以显示可能的内容。
答案 1 :(得分:2)
另一个突破性的解决方案
Func<Func<Fee, decimal>, decimal> totalFee = feeSelector =>
schoolFeesResult.Sum(x => x.Amount.Value / totalFees * feeSelector(x));
return new SchoolFees(
new Percentage(totalFee(f => f.TuitionFee.Value)),
new Percentage(totalFee(f => f.TravellingFee.Value)),
new Percentage(totalFee(f => f.ResidentialFee.Value))
);
甚至更短:
Func<Func<Fee, decimal>, Percentage> percentageOf = feeSelector =>
new Percentage(schoolFeesResult.Sum(x =>
x.Amount.Value / totalFees * feeSelector(x)));
return new SchoolFees(
percentageOf(f => f.TuitionFee.Value),
percentageOf(f => f.TravellingFee.Value),
percentageOf(f => f.ResidentialFee.Value)
);
答案 2 :(得分:1)
我使用WeightedAverage
的此实现作为IEnumerable<T>
的扩展方法:
public static double? WeightedAverage<TSource>(this IEnumerable<TSource> source
, Func<TSource, float> weightField
, Func<TSource, double> propertyToWeight)
{
var total = source.Sum(weightField);
var sum = source.Select(item => weightField(item) * propertyToWeight(item)).Sum();
return sum / total;
}
当然,有一些重载要处理single
,single?
和double
。也许你可以调整它以适应你想要达到的目标。
答案 3 :(得分:1)
我认为你可以把它放在另一个查询中,它也比以下更具可读性
var percentages = schoolFeesResult
.Select(x => new { SFR = x, AmoundDivFees = (x.Amount.Value / totalFees)})
.Select(x => new {
TuitionFee = x.AmoundDivFees * x.SFR.TuitionFee.Value,
TravellingFee = x.AmoundDivFees * x.SFR.TravellingFee.Value,
ResidentialFee = x.AmoundDivFees * x.SFR.ResidentialFee.Value
});
return new SchoolFees(
new Percentage(percentages.Sum(x => x.TuitionFee)),
new Percentage(percentages.Sum(x => x.TravellingFee)),
new Percentage(percentages.Sum(x => x.ResidentialFee)));
当然我无法测试它。