2012-05-29 17 views
9

LINQによって提供される.ToLookup関数に複数のキーを必要とする方法はありますか?複数のキーを参照する

これは最初は直感的ではないようですが、実際にこれを行う方法はないと思いますが、誰かが方法を知っていることを期待しています。

基本的には、2つの値、たとえばstringintをルックアップし、それらの2つの値でオブジェクトを取得できるようにしたいと考えています。

public class MyClass { 
     public string StringProp {get;set;} 
     public int IntProp {get;set;} 
     public object MoreData {get;set;} 
    } 

    public class Main { 
     public void Main() { 
     HashSet<MyClass> set = new HashSet<MyClass>(); 
     set.Add(new MyClass {StringProp = "a", IntProp = 1, MoreData = null}); 
     set.Add(new MyClass {StringProp = "c", IntProp = 4, MoreData = new object()}); 
     set.Add(new MyClass {StringProp = "a", IntProp = 2, MoreData = "upupdowndown"}); 
     set.Add(new MyClass {StringProp = "c", IntProp = 1, MoreData = string.Empty}); 
     set.Add(new MyClass {StringProp = "c", IntProp = 4, MoreData = string.Empty}); 
     // Using 'var' because I don't know how this would be defined. 
     // I recognize that this will not compile - but this is what I'm trying to do. 
     var lookup = set.ToLookup(x => x.StringProp && x.IntProp) 
     MyClass c = lookup["a", 1].First(); // Should return the first element 
     IEnumerable<MyClass> list = lookup["c", 4]; // Should return the 2nd and last elements 
     } 
    } 

答えて

17

私はこの種のもののためにTupleの使用します。

var lookup = set.ToLookup(x => Tuple.Create(x.StringProp, x.IntProp)); 
MyClass c = lookup[Tuple.Create("a", 1)].First(); 
IEnumerable<MyClass> list = lookup[Tuple.Create("c", 4)]; 
+0

私はこれがどのように役立つかを見ていけません。 – DarthVader

+0

おかげでガベ。私はそれを少し試して、それがどのように機能するかを伝えます。 – Merwer

4

あなたが本当に望むものではないが、しかし、うまく仕事を行います。

var r = set.ToLookup(x => new { x.StringProp, x.IntProp }); 
var f = r[ new { StringProp = "a", IntProp = 1 } ].First(); 
7

他の答えは、私が考えていた線に沿っているが、いくらか面倒であるルックアップから値を取得するたびに、タプルまたは匿名クラスを作成します。値を取得するためにインデクサーに文字列とintを貼り付けるだけでいいのではないでしょうか。インデクサーでルックアップをラップするための独自のクラスを作成することで、それを正確に行うことができます。ここで

public class MyLookup<T1, T2, TOut> 
{ 
    private ILookup<Tuple<T1, T2>, TOut> lookup; 
    public MyLookup(IEnumerable<TOut> source, Func<TOut, Tuple<T1, T2>> keySelector) 
    { 
     lookup = source.ToLookup(keySelector); 
    } 

    public IEnumerable<TOut> this[T1 first, T2 second] 
    { 
     get 
     { 
      return lookup[Tuple.Create(first, second)]; 
     } 
    } 

    //feel free to either expose the lookup directly, or add other methods to access the lookup 
} 

は、それが使用されているの例です。

IEnumerable<MyClass> data = null; //TODO populate with real data 
var lookup = new MyLookup<string, int, MyClass>(data 
    , item => Tuple.Create(item.StringProp, item.IntProp)); 

IEnumerable<MyClass> someValue = lookup["c", 4]; 
+0

これは本当に良いアイデアですが、Gabeの答えには、日々の開発の背後にあるコードを隠すのに十分な抽象概念をすでに行っていたとマークしました。 – Merwer

+0

これは多少面倒ですが、この種のことを頻繁にやらなければならない場合は、これが実装されます。 – Gabe

+0

@Gabe 'MyLookup'クラスは既に実装されているので、各インスタンスはあなたのソリューションよりも作成する必要はなく、実際に結果の"参照 "を使うのははるかに簡単です。 「MyLookup」を書く時間がかかったのかどうかは良い質問ですが、すでに完了していることを考えれば、それを使用するかどうかの質問は簡単に答えることができます。 – Servy

関連する問題