LINQ で加重平均を計算する 質問する

LINQ で加重平均を計算する 質問する

私の目標は、別のテーブルの主キーに基づいて、1 つのテーブルから加重平均を取得することです。

サンプルデータ:

表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 になるはずです。ありがとうございます。

ベストアンサー1

LINQ の拡張メソッドを次に示します。

public static double WeightedAverage<T>(this IEnumerable<T> records, Func<T, double> value, Func<T, double> weight)
{
    if(records == null)
        throw new ArgumentNullException(nameof(records), $"{nameof(records)} is null.");

    int count = 0;
    double valueSum = 0;
    double weightSum = 0;

    foreach (var record in records)
    {
        count++;
        double recordWeight = weight(record);

        valueSum += value(record) * recordWeight;
        weightSum += recordWeight;
    }

    if (count == 0)
        throw new ArgumentException($"{nameof(records)} is empty.");

    if (count == 1)
        return value(records.Single());

    if (weightSum != 0)
        return valueSum / weightSum;
    else
        throw new DivideByZeroException($"Division of {valueSum} by zero.");
}

これは、同じレコード内の別のフィールドに基づいて任意のデータ グループの加重平均を取得できるため、非常に便利になりました。

アップデート

ゼロ除算をチェックし、0 を返す代わりに、より詳細な例外をスローするようになりました。ユーザーが例外をキャッチし、必要に応じて処理できるようにします。

おすすめ記事