2011-12-14 12 views
3

私は現在、次の作業コードを持っています。しかし、それは痛いほど遅いです。私は、リストとしてではなくクエリとして保有物を渡すことが、物事を単純化し、速めるかもしれないことを知っていますが、いろいろな理由によりこれは不可能です。LINQ to Objects、List内のアイテムを更新する方法は?

新しいリストを作成せずに、保有物のリストを更新するにはどうすればよいですか?コードを改善するための他の提案?個人的に私はでリストを更新しようとしない

var targetRates = amdw.FXRates 
         .Where(rate => rate.BaseCurrency == toCurrency) 
         .ToList(); 

var query = from holding in holdings 
      join fxRateHolding in amdw.FXRates 
       on new { holding.Currency, holding.Date } equals 
       new { Currency = fxRateHolding.BaseCurrency, 
         Date = fxRateHolding.ValueDate } 
      join fxRateToCur in targetRates 
       on holding.Date equals fxRateToCur.ValueDate 
      select new { holding, fxRateHolding, fxRateToCur }; 

を:

internal List<DailyHoldingItem> TransformHoldingItemsToCurrency(List<DailyHoldingItem> holdings,string toCurrency) 
     { 
     //TODO - how to do this calculation in place, without creating a new list? 
     var query = (from holding in holdings 
        from fxRateHolding in amdw.FXRates 
        from fxRateToCur in amdw.FXRates 
        where 
        fxRateHolding.BaseCurrency == holding.Currency && 
        fxRateToCur.BaseCurrency == toCurrency && 
        fxRateHolding.ValueDate == holding.Date && 
        fxRateToCur.ValueDate == holding.Date 
        select new { holding, fxRateHolding, fxRateToCur }); 

     return query.Select(dhi => 
     { 
      decimal factor = dhi.fxRateToCur.Value/dhi.fxRateHolding.Value; 
      dhi.holding.MarketValue *= factor; 
      dhi.holding.Fee *= factor; 
      dhi.holding.Remuneration *= factor; 
      return dhi.holding; 
     }).ToList(); 

    } 
+0

一般的には、オブジェクトを編集するためにLINQを使用することはありません。 –

答えて

6

まあ、一つのことのためにあなたが参加し使用して、一度だけ有効な「ターゲット」の通貨を評価する物事をスピードアップすることができます場所と私(現在あなたのSelect呼び出しで行う)の既存の保有物を変更しないでしょう。既存の値を変更すると、コードを推論するのが難しくなります。そのため、LINQはであり、より機能的な方法でが設計されています。

+0

ありがとうございます。ジョインの構文を見てうれしいですが、私は複数の列でそれを行う方法を知らなかった。私はこのソリューションを使用し、Ufukからの回答のように、クエリのforeachを使用して更新しました。それは問題を解決し、クエリの速度は今や多かれ少なかれ即座になった。 – DavveK

+0

Jon Skeetはcool;) –

2

オブジェクトを更新するときにLINQを使用しないでください。 LINQは副作用がないと思われますので、変更する項目を取得してからforeachを実行する必要があります。

foreach(var dhi in query) 
{ 
    decimal factor = dhi.fxRateToCur.Value/dhi.fxRateHolding.Value; 
    dhi.holding.MarketValue *= factor; 
    dhi.holding.Fee *= factor; 
    dhi.holding.Remuneration *= factor; 
} 

また、List<T>で定義されているForEach関数をこのように使用することもできます。

query.ToList().ForEach(dhi => 
     { 
      decimal factor = dhi.fxRateToCur.Value/dhi.fxRateHolding.Value; 
      dhi.holding.MarketValue *= factor; 
      dhi.holding.Fee *= factor; 
      dhi.holding.Remuneration *= factor; 
     }); 

ジェフ・メルカドはコメントで指摘したように、それはそれでForEach()を呼び出すためのリストを作るためには良い考えではありません。

+2

'ForEach()'を呼び出すことができるように 'ToList()'を使うべきではありません... –

+0

OPのコードから始めるリストでなければなりませんまだ更新が行われるリスト。 –

+0

ポイントは、コレクションをリストに変換するのではなく、実際の 'foreach'ループを使用して、そのメソッドを使用できるようにすることです。 –

0

SQLでこれを行うことができます。すべての人がLINQの副作用を期待するわけではありませんが、すべてのC#は機能的な言語ではありません。ここで

は、あなたが何ができるかです:

  • つのプロパティを更新するだけで実行します。

    :複数のプロパティを更新するための

    from a in ab select a.prop = newVal;

  • を、あなたは以下のオプションを持っています

    1. 更新をmultiplで分割します。電子のLINQクエリ、それぞれがあなたが行うことができます(ただし、クエリ式で)LINQメソッドチェーンでは、次のfrom a in ab select new { x = a.prop = newVal, y = a.prop2 = newVal2 };

    2. を行い、単一のプロパティ(明らかにない最高のアイデア)

    3. を更新ab.Select(a=> { x = a.prop = newVal; y = a.prop2 = newVal2; return x; };

      (実際にはLinq to objects Updateにあります。この最後のメソッドを拡張メソッドにリファクタリングすると、クエリ式で使用できるようになり、意図を明確にすることができます)。

関連する問題