2012-04-07 9 views
3

先日、配列フィールドを含むオブジェクトのリストを取得し、オブジェクトが値になるマップ(つまり辞書)に変換するために、C#でコードを記述していましたが、オブジェクトの配列フィールドの各要素がキーになります。それはあまり意味がないかもしれないので、いくつかのコードを見てみましょう。私はでこれを行うにはしたくなかった、しかしC#のスカラflatMap.toMapの類似体

res0: scala.collection.immutable.Map[String,MyClass] = 
    Map(four -> [email protected], 
     three -> [email protected], 
     two -> [email protected], 
     six -> [email protected], 
     five -> [email protected], 
     one -> [email protected]) 

// Data class 
class MyClass(val keys:Array[String]) 

object MyClassTests { 

    // Dummy method just to get some sample data 
    def getMyClassList() = List(
    new MyClass(Array("one", "two", "three")), 
    new MyClass(Array("four", "five", "six"))) 


    def test() = { 
    val list = getMyClassList() 
    val map1 = list.view.flatMap(mc => mc.keys.map(_ -> mc)).toMap 
    // or, if you like for-comprehensions: 
    val map2 = (for (mc <- list.view; k <- mc.keys) yield k -> mc).toMap 
    map1 // or map2, same difference 
    } 
} 

REPLで、(追加書式で)私たちを与えることを実行する:スカラ座では、私はそれをこのような何かを行う可能性がありますScala、私はC#でそれをやりたかった。以下は、これに対する2つの可能な解決策を示しています.Test1()は非常に命令的な解決策であり、Test2()は私がその場で考えることができるほど類似しています。

だから私の質問はこれです:例は、一見無意味であるという事実を無視して、Test2をは(実際に)Scalaのコードに最も近い類似体であり、そしてそれはC#でこれを行うための最も簡潔な方法は何ですか?同じタスク(C#で)を達成するためのより簡潔な方法がありますか?

// Data class 
class MyClass { 
    public string[] Keys { get; set; } 

} 

class MyClassTests { 
    // Dummy method just to get some sample data 
    public static IList<MyClass> GetMyClassList() { 
     return new List<MyClass> { 
      new MyClass { 
       Keys = new[] {"one", "two", "three"} 
      }, 
      new MyClass { 
       Keys = new[] {"four", "five", "six"} 
      } 
     }; 
    } 

    public void Test1() { 
     var list = GetMyClassList(); 
     var validTypes = new Dictionary<string, MyClass>(); 
     foreach (var h in list) { 
      foreach (var key in h.Keys) 
       validTypes.Add(key, h); 
     } 
    } 

    public void Test2() { 
     var list = GetMyClassList(); 
     var validPartTypes = list 
      .SelectMany(mc => mc.Keys.Select(k => new KeyValuePair<string,MyClass>(k, mc))) 
      .ToDictionary(x => x.Key, x => x.Value); 
    } 
} 

答えて

4

KeyValuePair<>の代わりに匿名タイプを使用して、ビットコンサイザにすることができます。

var validPartTypes = list.SelectMany(mc => mc.Keys.Select(k => new { k, mc })) 
         .ToDictionary(x => x.k, x => x.mc); 

か、あなたは明確LINQクエリ構文を感じるならば、それは次のようになります。

var validPartTypes = (from mc in list 
         from k in mc.Keys 
         select new { k, mc }) 
         .ToDictionary(x => x.k, x => x.mc); 

は、しかし、あなたのコードが完全に有効であると私はC#でそれを達成するために任意のより良い方法が表示されません。

+0

匿名クラスでの呼び出しが良好です。コードを少しきれいに見せます。 –

0

あなたがあなた自身のLINQのような方法で作成することができます。

public static class MyLinq 
{ 
    public static IDictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> t) 
    { 
     return t.ToDictionary(p => p.Key, p => p.Value); 
    } 
} 

をし、また、あなたが代わりに.Select(k => new KeyValuePairToDictionaryを使用することができますが、それが原因で、多くの無用の辞書の作成の非常に遅い方法です:

public void Test2() { 
    var list = GetMyClassList(); 
    var validPartTypes = list 
     .SelectMany(mc => mc.Keys.ToDictionary(k => mc)) 
     .ToDictionary(); 
}