2011-08-04 11 views
1

次のようなオブジェクトグラフが表示されます。LINQ(コレクション内のコレクション)でコードを簡略化する

A --> B[] --> B1[] 
      --> B2[] 
    --> C[] 

I、メンバー/ B1及びB2の特性ならびにb2.Code []はC内のどこかに表示されていることを確実に特定の条件をチェックする必要があります。すべての条件が満たされたら、CとB配列の要素からの変数を使用して新しいオブジェクトを構築する必要があります。私の現在の試みは以下に示されていますが、これがLINQでより簡潔にできるかどうか疑問に思っていますか?

A a = GetA(); 
    List<MyTest> tsts = new List<MyTest>(); 
    foreach (B b in a.B) 
    { 
     foreach (B1 b1 in b.B1) 
     { 
      if (b1.State == ("READY")) 
      { 
       foreach (B2 b2 in b.B2) 
       { 
        var tst = (from c in a.C 
          where c.Code == b2.Code && !c.IsRedundant 
          select new MyTest 
          { 
           Code = c.Code, 
           BVal = b.BVal, 
           C1Val = c.C1      
          }).FirstOrDefault(); 
        if (tst != null) 
         tsts.Add(tst); 
        break; 
       } 
      } 
     } 
    } 

答えて

2

絶対に。この上

var tests = from b in GetA().B 
      from b1 in b.B1 
      where b1.State == "READY" 
      from b2 in b.B2.Take(1) 
      from c in a.C 
         .Where(x => x.Code == b2.Code && !c.IsRedundant) 
         .Take(1) 
      select new MyTest 
      { 
       Code = c.Code, 
       BVal = b.BVal, 
       C1Val = c.C1      
      }; 

var testList = tests.ToList(); 

いくつかの注意事項:基本的にはそれぞれの新しいforeachはおおよそ余分from句に相当

  • あなたが実際にb1を使用したことがないしていることを奇妙に思えるが、あなたは余分を作成します「準備完了」状態にある各b1のテストセット。
  • foreach (B2 b2 ...)ループ内の無条件breakは基本的に我々は唯一のこれまで一度ループ本体を実行すること - それゆえTake(1)
  • 私は内側のクエリを持って、なぜあなたが唯一の最も内側のクエリの最初の結果を使用する方法がある(表現最大1つの結果

を取得するためのTake(1)コールと拡張メソッド)を介してこれらの奇妙の一部を除去することができることを十分に可能だ - それはあなたが本当に達成しようとしているものは明らかではありませんので、私はちょうどましたできるだけ忠実に元のクエリをコードに再現させようとしました。

+0

ありがとうございます。それは本当に有望そうです。 奇妙なことに関して私のコードを投稿するのは少し面白かったかもしれませんが、あなたのメモに対処するためには少し面倒でした。 - 実際にはb1から何も取ることはありませんが、b1.Stateが "READY"でない場合はリストに追加したくありません。 - FirstOrDefaultとbreakは、一致するxが0または1になるように使用してください。コード== b2.Code。したがって、一致するものがあればそれを使用します。それ以外の場合は、最外ループの次のアイテム(つまり、b)の処理を**本当に**続けるべきです。通常、b1配列には最大で2つの要素があるので、私は中断することはありませんでした。 –

関連する問題