5

先日、C#でコードを記述して、それぞれに配列フィールドを含むオブジェクトのリストを取得し、それをマップ(つまり辞書)に変換して、オブジェクトが値になり、オブジェクトの配列フィールドの各要素がキー。それはあまり意味がないかもしれないので、いくつかのコードを示しましょう。Scalaでは、次のようなことをするかもしれません。

// 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で実行すると、(フォーマットが追加されて)次のようになります。

res0: scala.collection.immutable.Map[String,MyClass] = 
    Map(four -> MyClass@4ee31ef2, 
        three -> MyClass@69bc6271, 
        two -> MyClass@69bc6271, 
        six -> MyClass@4ee31ef2, 
        five -> MyClass@4ee31ef2, 
        one -> MyClass@69bc6271)

しかし、私はこれを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

2 に答える 2

7

の代わりに匿名タイプを使用し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#でそれを実現するためのより良い方法はありません。

于 2012-04-07T08:34:28.720 に答える
1

独自の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);
    }
}

ToDictionaryまた、の代わりに使用することもできますが.Select(k => new KeyValuePair、多くの役に立たない辞書が作成されるため、非常に時間がかかります。

public void Test2() { 
    var list = GetMyClassList(); 
    var validPartTypes = list 
        .SelectMany(mc => mc.Keys.ToDictionary(k => mc)) 
        .ToDictionary(); 
} 
于 2012-04-07T08:32:23.433 に答える