题
我的目标是根据另一个表主键从一张桌子获得加权平均值。
示例数据:
表格1
Key WEIGHTED_AVERAGE
0200 0
table2
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<T>(this IEnumerable<T> records, Func<T, double> value, Func<T, double> 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);
这变得非常方便,因为我可以根据同一记录中的另一个字段获得任何组数据的加权平均值。
更新
现在,我检查零除以零,并投掷更详细的异常,而不是返回0。允许用户根据需要捕获异常并处理。
其他提示
如果您确定表2中的每个外键都有相应的记录,则可以避免加入仅组成一个组。
在这种情况下,LINQ查询就是这样:
IEnumerable<int> 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);
更新
这就是您可以获得的方式 wheighted_average
对于特定 foreign_key
.
IEnumerable<Record> 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方法是避免在两个单独的总和操作中汇总记录时执行查询两次。
(将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);
不隶属于 StackOverflow