Scala flatMap.toMap analogs in C #

I wrote code in C # the other day to take a list of objects, each containing an array field, and convert it to a map (i.e. a dictionary) where the objects become values ​​and each element of the object array becomes a key. It might not make a lot of sense, so show the code. In Scala, I can do it something like this:

// 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
  }
}

      

Doing this in the REPL gives us (with added formatting):

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)

      

However, I didn't want to do this in Scala, I wanted to do it in C #. Below are two possible solutions to this test: Test1 () is a very imperative solution, and Test2 () is as analogous as I could think of on the spot.

So, my question: . Ignoring the fact that this example seems to be insane, is Test2 () really the closest analogue to Scala code and is it the most concise way to do this in C #? Is there a more concise way to accomplish the same task (in 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);
    }
}

      

+3


source to share


2 answers


You can use an anonymous type instead KeyValuePair<>

to make it a bit of a conciser:

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

      

or, if you get a feel for the LINQ clearer query syntax, it would be:



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

      

However, your code is perfectly plausible and I don't see a better way to do this in C #.

+4


source


You can create your own LINQ-like method:

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);
    }
}

      



And also you can use ToDictionary

instead .Select(k => new KeyValuePair

, but its a very slow way due to the creation of many useless dictionaries:

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

      

0


source







All Articles