用LINQ计算加权平均值
我的目标是根据另一个表主键从一个表中获得加权平均值。
示例数据:
表格1
Key WEIGHTED_AVERAGE 0200 0
表2
ForeignKey Length Value 0200 105 52 0200 105 60 0200 105 54 0200 105 -1 0200 47 55
我需要根据段的长度得到加权平均值,我需要忽略-1的值。 我知道如何在SQL中执行此操作,但我的目标是在LINQ中执行此操作。 它在SQL中看起来像这样:
SELECT Sum(t2.Value*t2.Length)/Sum(t2.Length) AS WEIGHTED_AVERAGE FROM Table1 t1, Table2 t2 WHERE t2.Value -1 AND t2.ForeignKey = t1.Key;
我仍然是LINQ的新手,并且很难弄清楚我将如何翻译它。 结果加权平均值应该大约为55.3。 谢谢。
我这样做足以让我为LINQ创建了一个扩展方法。
public static double WeightedAverage(this IEnumerable records, Func value, Func weight) { double weightedValueSum = records.Sum(x => value(x) * weight(x)); double weightSum = records.Sum(x => weight(x)); if (weightSum != 0) return weightedValueSum / weightSum; else throw new DivideByZeroException("Your message here"); }
获得数据子集后,调用看起来像这样。
double weightedAverage = records.WeightedAverage(x => x.Value, x => x.Length);
这已变得非常方便,因为我可以根据同一记录中的另一个字段获得任何数据组的加权平均值。
更新
我现在检查除以零并抛出更详细的exception而不是返回0.允许用户捕获exception并根据需要处理。
如果你确定Table2中的每个外键都有一个相应的记录,那么你可以避免只是组成一个组。
在这种情况下,LINQ查询是这样的:
IEnumerable wheighted_averages = from record in Table2 where record.PCR != -1 group record by record.ForeignKey into bucket select bucket.Sum(record => record.PCR * record.Length) / bucket.Sum(record => record.Length);
UPDATE
这是你如何获得特定foreign_key
的wheighted_average
。
IEnumerable records = (from record in Table2 where record.ForeignKey == foreign_key where record.PCR != -1 select record).ToList(); int wheighted_average = records.Sum(record => record.PCR * record.Length) / records.Sum(record => record.Length);
获取记录时调用的ToList方法是避免在两个单独的Sum操作中聚合记录时执行两次查询。
(回答jsmith对上述答案的评论)
如果您不希望循环访问某些集合,可以尝试以下操作:
var filteredList = Table2.Where(x => x.PCR != -1) .Join(Table1, x => x.ForeignKey, y => y.Key, (x, y) => new { x.PCR, x.Length }); int weightedAvg = filteredList.Sum(x => x.PCR * x.Length) / filteredList.Sum(x => x.Length);