10

次のようなループがあります。複数の SUM を使用して同じことを行うことはできますか?

foreach (var detail in ArticleLedgerEntries.Where(pd => pd.LedgerEntryType == LedgerEntryTypeTypes.Unload &&
                                                                pd.InventoryType == InventoryTypes.Finished))
{
     weight += detail.GrossWeight;
     length += detail.Length;
     items  += detail.NrDistaff;
}
4

5 に答える 5

8

技術的に言えば、あなたが持っているものは、おそらくあなたが求めていることを行うための最も効率的な方法です. ただし、IEnumerable<T> に Each という拡張メソッドを作成すると、より簡単になる可能性があります。

public static class EnumerableExtensions
{
    public static void Each<T>(this IEnumerable<T> col, Action<T> itemWorker)
    {
        foreach (var item in col)
        {
            itemWorker(item);
        }
    }
}

そして、次のように呼び出します。

// Declare variables in parent scope
double weight;
double length;
int items;

ArticleLedgerEntries
    .Where(
        pd => 
           pd.LedgerEntryType == LedgerEntryTypeTypes.Unload &&
           pd.InventoryType == InventoryTypes.Finished
    )
    .Each(
        pd => 
        {
            // Close around variables defined in parent scope
            weight += pd.GrossWeight; 
            lenght += pd.Length;
            items += pd.NrDistaff;
        }
    );

更新: 1 つだけ追加のメモ。上記の例はクロージャに依存しています。変数 weight、length、および items は、親スコープで宣言する必要があります。これにより、itemWorker アクションへの各呼び出しを超えてそれらを持続させることができます。わかりやすくするために、これを反映するように例を更新しました。

于 2009-11-09T23:00:11.277 に答える
5

3回呼び出すこともできますSumが、ループが3回になるため、処理が遅くなります。

例えば:

var list = ArticleLedgerEntries.Where(pd => pd.LedgerEntryType == LedgerEntryTypeTypes.Unload
                                   && pd.InventoryType == InventoryTypes.Finished))

var totalWeight = list.Sum(pd => pd.GrossWeight);
var totalLength = list.Sum(pd => pd.Length);
var items = list.Sum(pd => pd.NrDistaff); 

実行が遅れるため、Where毎回呼び出しを再評価しますが、それはあなたの場合はそのような問題ではありません。これは、を呼び出すことで回避できますがToArray、配列の割り当てが発生します。(そしてそれはまだ3つのループを実行します)

ただし、エントリの数が非常に多い場合や、このコードをタイトループで実行している場合を除いて、パフォーマンスについて心配する必要はありません。


編集本当にLINQを使用したい場合は、次Aggregateのように誤用する可能性があります。

int totalWeight, totalLength, items;

list.Aggregate((a, b) => { 
    weight += detail.GrossWeight;
    length += detail.Length;
    items  += detail.NrDistaff;
    return a;
});

これは驚くほど醜いコードですが、ストレートループとほぼ同じように実行されるはずです。

アキュムレータで合計することもできますが(以下の例を参照)、これにより、リスト内のすべてのアイテムに一時オブジェクトが割り当てられます。これはばかげた考えです。(匿名タイプは不変です)

var totals = list.Aggregate(
    new { Weight = 0, Length = 0, Items = 0},
    (t, pd) => new { 
        Weight = t.Weight + pd.GrossWeight,
        Length = t.Length + pd.Length,
        Items = t.Items + pd.NrDistaff
    }
);
于 2009-11-09T22:10:22.857 に答える
2

true - 1 でグループ化することもできます (これは、実際にはアイテムのいずれかを含めてから、それらをカウントまたは合計します)。

 var results = from x in ArticleLedgerEntries
                       group x by 1
                       into aggregatedTable
                       select new
                                  {
                                      SumOfWeight = aggregatedTable.Sum(y => y.weight),
                                      SumOfLength = aggregatedTable.Sum(y => y.Length),
                                      SumOfNrDistaff = aggregatedTable.Sum(y => y.NrDistaff)
                                  };

実行時間に関しては、ループとほぼ同じです (一定の加算あり)。

于 2011-10-30T05:37:36.843 に答える
0

Ok。LINQ を使用してこれを行う簡単な方法がないことを認識しています。それほど悪くないことがわかったので、 foreach ループを使用します。皆さんのお陰で

于 2009-11-10T08:39:51.697 に答える
0

このトピックの回答を使用して、このピボット スタイルを実行できます: LINQ を使用してデータをピボットすることは可能ですか?

于 2009-11-09T22:21:39.887 に答える