2012-03-18 11 views
3

私は3つの別々の辞書を持つオブジェクトを持っています。各辞書のvalueパラメーターは、同じインターフェースを実装します。 3つの辞書を1つにまとめて1つのクエリを実行し、クエリの結果が単一のIEnumerableになる最良の方法は何ですか?3つの別々のコレクションでの単一のLINQクエリ

私はこれを達成しようとしています。私のDataSetオブジェクトには3つの辞書が含まれていますが、それぞれは非常に小さくすべきです(理論的には100までの要素を含むことができますが、極端な場合は常に20未満、通常は6以下です)。

GetAllId()メソッドの目的は、各辞書の各要素のいくつかのプライベートフィールドのIDを取得し、単一のIEnumerableとして返します。ディクショナリ値オブジェクトはすべて、IIdQueryableを実装しています。これは、オブジェクト内に必要なすべてのIdを抽出する単一のメソッドを定義します。

私は自分が望むものを達成する方法について2つのアイデアを持っていますが、これを達成するためのよりよい方法があるかどうかはわかりません。各OBJECので

public class DataSet 
{ 
    Dictionary<Int32, Foo> dict1; 
    Dictionary<CustomKey, Bar> dict2; 
    Dictionary<Int32, Boo> dict3; 

    public IEnumerable<Int32> GetAllId 
    { 
     // need to retrieve Id from dict1, dict2, and dict3. 
     // implementation ideas below 
    } 
} 

オプション1

public IEnumerable<Int32> GetAllId 
{ 
    var q1 = dict.Values.SelectMany(g => g.GetId()); 
    var q2 = dict.Values.SelectMany(g => g.GetId()); 
    var q3 = dict.Values.SelectMany(g => g.GetId()); 

    return q1.Concat(q2).Concat(q3); 
} 

オプション2

public IEnumerable<Int32> GetAllId 
{ 
    var c1 = dict1.Values.Cast<IIdQueryable>(); 
    var c2 = dict2.Values.Cast<IIdQueryable>(); 
    var c3 = dict2.Values.Cast<IIdQueryable>(); 

    var collection = c1.Concat(c2).Concat(c3); 

    return collection.SelectMany(g => g.GetId()); 
} 

方法#3

同じインターフェイスを実装していますが、キャストせずに3つのオブジェクトすべてに対して単一のLINQクエリを実行することは可能ですか?

私は個人的にはメソッド#1が好きです。何もキャストする必要はありませんが、メソッド#2は読みやすくなると思います。それが必要とされる場合

は、ここでは、インターフェイスが実装されているかの目安です

public interface IIdQueryable 
{ 
    IEnumerable<Int32> GetId(); 
} 

public class Foo : IIdQueryable 
{ 
    public IEnumerable<Int32> GetId() 
    { 
     //returns Id of all elements in this object 
    } 
} 

public class Bar : IGuidQueryable 
{ 
    public IEnumerable<Int32> GetId() 
    { 
     //returns Id of all elements in this object 
    } 
} 

public class Boo : IGuidQueryable 
{ 
    public IEnumerable<Int32> GetId() 
    { 
     //returns Id of all elements in this object 
    } 
} 

EDIT:質問のタイトルは何ができるか、私が望んでいたのソースは(その

ですキャストなしで1つのクエリで3つのルックアップをすべて実行します)。私は上記を明確にした。

答えて

2

あなただけの最初のアプローチで1つのSelectMany呼び出し必要があります、パフォーマンスに影響が別々のクエリを維持し、同じように連結したものを返すことではありませんけれども

public IEnumerable<Int32> GetAllId() 
{ 
    return dict1.Values 
       .Select(x => x.GetId()) 
       .Concat(dict2.Values.Select(x=> x.GetId())) 
       .Concat(dict3.Values.Select(x => x.GetId())) 
       .SelectMany(x => x); 
} 

個人的に私は一緒にこのダクトテープではないだろうがあなたは、最初の例では、すでにやった - それは私には、より読みやすいです:

public IEnumerable<Int32> GetAllId() 
{ 
    var q1 = dict1.Values.Select(g => g.GetId()); 
    var q2 = dict2.Values.Select(g => g.GetId()); 
    var q3 = dict3.Values.Select(g => g.GetId()); 

    return q1.Concat(q2) 
      .Concat(q3) 
      .SelectMany(x => x); 
} 

は今、これはすでに第二のアプローチにかなり近いに見える - しかし、何のキャストは必要ありません。

+1

実際、彼は最初の例では 'SelectMany'が必要です。 'Select'は' IEnumerable 'が必要なときにIEnumerable >を返します。あなたの提案はコンパイルされません。私は@ psubsee2003の最初のオプションはかなり良いと思います。 –

+0

それは私がそれを見落としていたからです。 – BrokenGlass

+0

@BrokenGlass - 私はそれをどこに置くかについて選択肢がある文脈で.SelectMany()を扱ったことがありません。一度しか呼び出されないように移動を提案したパフォーマンスの理由はありますか?それとももっと読めるようになったと思いましたか? – psubsee2003

関連する問題