2011-09-11 11 views
1

指定されたクラス:1つのlinq文で2つ以上の値をSum()することはできますか?

public class FooAmounts 
int Id 
decimal Month1 
decimal Month2 
... 
decimal Month12 
decimal Year2 
decimal Year3 
decimal Future 

私は毎月の合計を持っている単一の新しいFooAmountsを作成したいと思います

5つのエントリ(!funnily十分同上の1-5)とIEnumerable<FooAmounts> /年持っていますただし、Id == 1 + Id == 2の場合のみ

var footle = (from f in foolist 
where f.Id == 1 || f.Id == 2 
select new FooAmounts{ 
Month1 = Sum(month 1s), 
Month2 = Sum(month 2s), 
etc etc. 
Future = Sum(futures) 
).FirstOrDefault(); 

私は再作成するには、このT-SQLしようとしています:

select SUM(Month1) as Month1, SUM(Month2) as Month2, SUM(Month3) as Month3 from FooAmount where Id=1 or Id=2" 

私はgroup by f.Id into grp句を使用して、同様のacheiveすることができますが、その2つの項目で私を残し、したがって、私が最初に使用することはできません/ FoD、私は手動でそれらをまだ残しておく必要があることを意味...私はどこかでトリックを欠場する必要がありますように思える?

注:FirstOrDefault()はそこにしかないので、1つのオブジェクトを含む列挙型ではなく、単一のオブジェクトを取得します。私は(おそらく間違って!)これは常に1つのアイテムだけを返すべきだと思う...計算に入ったアイテムの数に関係なく、Sum()の結果は1つだけです。

答えて

1

値が1つであるか複数であるかに関わらず、合計の最初の結果を取得することは意味がありません。

私は10人を持っている場合は、私が最初のものの年齢を見つけることができる、または私はそれらのすべての年齢の合計を見つけることができます - しかし、私は年齢の最初合計を見つけることができません。あなたは次のようにすることができます:

var matches = fooList.Where(f => f.Id == 1 || f.Id == 2); 

var sum = new FooAmounts { Month1 = matches.Sum(f => f.Month1), 
          Month2 = matches.Sum(f => f>Month2), 
          ... }; 

これで、もちろん複数回クエリが実行されます。代わりに、クエリを具現化し、その上で加算を行うことができます。

// Materialize the result so we only filter once 
var matches = fooList.Where(f => f.Id == 1 || f.Id == 2).ToList(); 

var sum = new FooAmounts { Month1 = matches.Sum(f => f.Month1), 
          Month2 = matches.Sum(f => f>Month2), 
          ... }; 

または代わりにあなたが集計使用できます。

var sum = fooList.Where(f => f.Id == 1 || f.Id == 2) 
        .Aggregate(new FooAmounts(), // Seed 
          (sum, item) => new FooAmounts { 
           Month1 = sum.Month1 + item.Month1, 
           Month2 = sum.Month2 + item.Month2, 
           ... 
          }); 

をこれだけ大きなを作成し、一度のシーケンスを反復し、しませんメモリ内にバッファを作成しますが、反復するたびに多くのFooAmountsインスタンスが作成されます。

あなたはもちろん、場所にアキュムレータを変更することができます:

var sum = fooList.Where(f => f.Id == 1 || f.Id == 2) 
        .Aggregate(new FooAmounts(), // Seed 
          (sum, item) => { 
           sum.Month1 += item.Month1; 
           sum.Month2 += item.Month2; 
           ... 
           return sum; 
          }); 

のはわずか厄介な私にを感じているが、それはは本当には、悪い方法では副作用を持っていないこととにかくコール内で初期化されているオブジェクトを変更しているだけです。

+0

おそらくひどく言われているApols。私は単純に、オブジェクトのリスト(すでに持っているもの)か、Sum(s => s.property)を毎月... Year私が望んでいた。 – BlueChippy

+0

@BlueChippy:いくつかのオプションで投稿を編集しました。私はこれらのオプションを超えてシンプルでエレガントなものはないと思う。 –

+0

ありがとうございましたJon - 私は、このt-sqlの同等の "(1月にSUM1を選択し、Month2としてSUM(Month2)、FooAmountからMonth3 をId = 1またはId = 2"として再作成したいと考えていました。 – BlueChippy

関連する問題