Considering the performance of dictionary key lookups and deletes since they are hash operations, and considering the wording of the question was best way, I think that below is a perfectly valid approach, and the others are a bit over-complicated, IMHO.
public static void MergeOverwrite<T1, T2>(this IDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
{
if (newElements == null) return;
foreach (var e in newElements)
{
dictionary.Remove(e.Key); //or if you don't want to overwrite do (if !.Contains()
dictionary.Add(e);
}
}
OR if you're working in a multithreaded application and your dictionary needs to be thread safe anyway, you should be doing this:
public static void MergeOverwrite<T1, T2>(this ConcurrentDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
{
if (newElements == null || newElements.Count == 0) return;
foreach (var ne in newElements)
{
dictionary.AddOrUpdate(ne.Key, ne.Value, (key, value) => value);
}
}
You could then wrap this to make it handle an enumeration of dictionaries. Regardless, you're looking at about ~O(3n) (all conditions being perfect), since the .Add()
will do an additional, unnecessary but practically free, Contains()
behind the scenes. I don't think it gets much better.
If you wanted to limit extra operations on large collections, you should sum up the Count
of each dictionary you're about to merge and set the capacity of the the target dictionary to that, which avoids the later cost of resizing. So, end product is something like this...
public static IDictionary<T1, T2> MergeAllOverwrite<T1, T2>(IList<IDictionary<T1, T2>> allDictionaries)
{
var initSize = allDictionaries.Sum(d => d.Count);
var resultDictionary = new Dictionary<T1, T2>(initSize);
allDictionaries.ForEach(resultDictionary.MergeOverwrite);
return resultDictionary;
}
Note that I took in an IList<T>
to this method... mostly because if you take in an IEnumerable<T>
, you've opened yourself up to multiple enumerations of the same set, which can be very costly if you got your collection of dictionaries from a deferred LINQ statement.
dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
– Benjoldict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)
– BrucedictA.Concat(dictB.Where(kvp => !dictA.ContainsKey(kvp.Key))).ToDictionary(kvp=> kvp.Key, kvp => kvp.Value)
. – Suncat2000