I was writing some 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. dictionary) where the objects become the values, and each element of the object's array field become the keys. That might not have made much sense, so let's show some code. In Scala, I might 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
}
}
Running that in the REPL, gives us (with formatting added):
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#. The below presents two possible solutions to this, Test1() being a very imperative-style solution, and Test2() being as close an analogue as I could think up on the spot.
So my question is this: Ignoring the fact that the example is seemingly inane, is Test2() really the closest analogue to the 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);
}
}
You can use an anonymous type instead of the KeyValuePair<>
to make it a bit conciser:
var validPartTypes = list.SelectMany(mc => mc.Keys.Select(k => new { k, mc }))
.ToDictionary(x => x.k, x => x.mc);
or, if you feel LINQ query syntax clearer, 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 valid and I don't see any much better way to accomplish that in C#.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With