Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a Dictionary from one type to another

How can I convert a Dictionary(Of TypeA, TypeB) to a Dictionary(Of TypeC, TypeD)? There is an implicit cast when converting (let's say the second dictionary is String, String), so this process should be automatic, right? I just can't figure out an elegant way to do this.

The language is VB.NET, but I can read and convert C# if you're more comfortable with that.

like image 961
qJake Avatar asked Jun 28 '11 14:06

qJake


2 Answers

I would use Linq for cases like this. There's a ToDictionary() method that converts any generic IEnumerable (and a Dictionary<TA,TB> is an IEnumerable<KeyValuePair<TA,TB>>) to a Dictionary by taking two projections of the Enumerable element to produce a key and value for the dictionary. It makes these kinds of conversions very simple:

Dictionary<TypeA, TypeB> myDictionary = new Dictionary<TypeA, TypeB>
                                            { 
                                               /*initialization here*/ 
                                            };
Dictionary<TypeC, TypeD> myChangedDictionary = 
    myDictionary.ToDictionary(x=>x.Key.AsTypeC(), x=>x.Value.AsTypeD())

AsTypeC() and AsTypeD() are placeholders for whatever conversion is necessary to go from A/B to C/D. You suggested the second Dictionary was a Dictionary<string,string>; in that case you'd simply ToString() both of them (if you've overridden that method) or use the Key/Value in some String.Format operation.

like image 199
KeithS Avatar answered Oct 11 '22 23:10

KeithS


 public static class DictionaryExtensions {
     public static Dictionary<TProjectedKey, TProjectedValue> ConvertDictionary<
         TKey,
         TValue,
         TProjectedKey, 
         TProjectedValue
     >(
         this Dictionary<TKey, TValue> dictionary,
         Func<TKey, TProjectedKey> keyProjection,
         Func<TValue, TProjectedValue> valueProjection
     ) {
         Contract.Requires(dictionary != null);
         Contract.Requires(keyProjection != null);
         Contract.Requires(valueProjection != null);
         Contract.Requires(dictionary.Select(kvp => keyProjection(kvp.Key))
                                     .AllValuesAreUnique()
                          );
         return dictionary.ToDictionary(
             kvp => keyProjection(kvp.Key),
             kvp => valueProjection(kvp.Value)
         );
     }
 }

The last Contract.Requires is saying that keyProjection is required to be one-to-one on dictionary.Keys. The method IEnumerable<TSource>.AllValuesAreUnique is an extension method that I'm sure you can figure out how to write.

Then, you can say:

Dictionary<Foo, Bar> dictionary = // some dictionary;
var projection = dictionary.ConvertDictionary(
    foo => foo.ToString(),
    bar => bar.ToString()
);

so this process should be automatic, right?

I see no reason why this should be automatic. If the types are different, their hash codes are likely different, etc. The "converted" dictionary effectively needs to be built from scratch.

like image 39
jason Avatar answered Oct 11 '22 23:10

jason