549

What's the best way to merge 2 or more dictionaries (Dictionary<T1,T2>) in C#? (3.0 features like LINQ are fine).

I'm thinking of a method signature along the lines of:

public static Dictionary<TKey,TValue>
                 Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);

or

public static Dictionary<TKey,TValue>
                 Merge<TKey,TValue>(IEnumerable<Dictionary<TKey,TValue>> dictionaries);

EDIT: Got a cool solution from JaredPar and Jon Skeet, but I was thinking of something that handles duplicate keys. In case of collision, it doesn't matter which value is saved to the dict as long as it's consistent.

orip
  • 66,082
  • 20
  • 111
  • 144
  • 200
    Unrelated, but for anyone looking to merge just two dictionaries without duplicate key checks, this works nicely: `dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)` – Benjol Dec 14 '11 at 07:31
  • 7
    @Benjol you could have added this in answer section – M.Kumaran Sep 02 '13 at 13:54
  • 4
    Clojure's merge in C#: `dict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)` – Bruce Jun 01 '15 at 04:00
  • 6
    @Benjol: eliminate duplicates by preferring entries from the first dictionary with `dictA.Concat(dictB.Where(kvp => !dictA.ContainsKey(kvp.Key))).ToDictionary(kvp=> kvp.Key, kvp => kvp.Value)`. – Suncat2000 Apr 13 '20 at 13:26

27 Answers27

351

This partly depends on what you want to happen if you run into duplicates. For instance, you could do:

var result = dictionaries.SelectMany(dict => dict)
                         .ToDictionary(pair => pair.Key, pair => pair.Value);

That will throw an exception if you get any duplicate keys.

EDIT: If you use ToLookup then you'll get a lookup which can have multiple values per key. You could then convert that to a dictionary:

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());

It's a bit ugly - and inefficient - but it's the quickest way to do it in terms of code. (I haven't tested it, admittedly.)

You could write your own ToDictionary2 extension method of course (with a better name, but I don't have time to think of one now) - it's not terribly hard to do, just overwriting (or ignoring) duplicate keys. The important bit (to my mind) is using SelectMany, and realising that a dictionary supports iteration over its key/value pairs.

Florian Winter
  • 3,381
  • 1
  • 33
  • 52
Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • 3
    To actually merge the values instead of just taking them from the first dictionary you can replace group => group.First() with group => group.SelectMany(value => value) in Jon Skeet's edited answer. – andreialecu Apr 13 '11 at 15:53
  • 3
    Now I'm wondering that GroupBy would be better suited than ToLookup ? I think ILookup just adds an indexer, size property and contains method on top of IGrouping - so it got to be a tiny little bit faster ? – toong May 30 '13 at 15:25
  • 2
    @toong: Either should be fine, to be honest. Using `GroupBy` could indeed be a little bit more efficient - but I doubt that it would be significant either way. – Jon Skeet May 30 '13 at 17:06
  • A minor detail: along with most other answers, this doesn't deal with the situation where (some of) the input dictionaries are using a non-default comparer: e.g. a case-insensitive string key. A completely general solution should allow the caller to specify the comparer for the target dictionary. Or copy into an existing dictionary, like Jonas Stensved's answer. – Joe Dec 04 '13 at 07:21
  • 1
    @Joe: That's simple enough by providing the comparer to the `ToDictionary` method call. I'd prefer to keep the answer simpler for the more common case though, and I'd hope that anyone who needs a custom comparer is capable of finding the relevant overload. – Jon Skeet Dec 04 '13 at 07:23
  • Just a note that if you use `.Last` instead, it will "update" the original values instead of locking on and never changing. – Greg Mar 05 '21 at 17:14
296

I would do it like this:

dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));

Simple and easy. According to this blog post it's even faster than most loops as its underlying implementation accesses elements by index rather than enumerator (see this answer).

It will of course throw an exception if there are duplicates, so you'll have to check before merging.

SIRHAMY
  • 129
  • 1
  • 7
Jonas Stensved
  • 11,732
  • 3
  • 45
  • 66
  • 181
    If duplicates matter, use `dictionaryFrom.ToList().ForEach(x => dictionaryTo[x.Key] = x.Value)`. This way the values from `dictionaryFrom` override the value for a possibly existing key. – okrumnow Feb 21 '12 at 09:46
  • 7
    This is unlikely to be faster than a loop - you forget that ToList() actually ends up copying the dictionary. Faster to code though! ;-) – Søren Boisen Mar 20 '14 at 16:06
  • 7
    This is faster.. Since ToList() actually doesn't end up copying the dictionary, it just copies the references of elements inside them. Basically the list object itself will have a new address in memory, the objects are same !! – GuruC Mar 18 '15 at 01:19
  • 6
    Blog post vanished but yay Wayback machine: http://web.archive.org/web/20150311191313/http://diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx – CAD bloke Mar 18 '16 at 08:59
  • How about memory allocation? The link is broken so its unclear how it can be better than foreach which doesn't need to allocate memory for new List. – Valentin Kuzub Nov 28 '16 at 13:30
  • 1
    Hmm, better than *the* Jon Skeet's answer, I presume. – Sнаđошƒаӽ Dec 12 '16 at 06:43
  • 2
    *better* `Jon Skeet's answer` ? ***Jon Skeet*** – Kiquenet Feb 26 '18 at 12:15
108

This doesn't explode if there are multiple keys ("righter" keys replace "lefter" keys), can merge a number of dictionaries (if desired) and preserves the type (with the restriction that it requires a meaningful default public constructor):

public static class DictionaryExtensions
{
    // Works in C#3/VS2008:
    // Returns a new dictionary of this ... others merged leftward.
    // Keeps the type of 'this', which must be default-instantiable.
    // Example: 
    //   result = map.MergeLeft(other1, other2, ...)
    public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others)
        where T : IDictionary<K,V>, new()
    {
        T newMap = new T();
        foreach (IDictionary<K,V> src in
            (new List<IDictionary<K,V>> { me }).Concat(others)) {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K,V> p in src) {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

}
Dave
  • 7,614
  • 10
  • 56
  • 99
  • Well done. This was exactly what I needed. Nice use of generics. Agreed that the syntax is a bit awkward, but nothing you can do about it. – Peter M Apr 23 '10 at 17:09
  • 3
    I liked this solution, but there is a caveat: if the `this T me` dictionary was declared using `new Dictionary(StringComparer.InvariantCultureIgnoreCase)` or something similar, the resulting dictionary will not retain the same behavior. – João Portela Jan 09 '14 at 14:51
  • 6
    If you make `me` a `Dictionary`, you can then do `var newMap = new Dictionary(me, me.Comparer);`, and you also avoid the extra `T` type parameter. – ANeves thinks SE is evil Jan 30 '14 at 11:25
  • 2
    Does someone have an example of how to use this beast? – Tim Jan 27 '15 at 18:54
  • 2
    @Tim: I added an example for the beast below, I added the solution by ANeves and the result is a more domesticated beast :) – keni Mar 22 '15 at 04:25
55

The trivial solution would be:

using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
    Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
    var result = new Dictionary<TKey, TValue>();
    foreach (var dict in dictionaries)
        foreach (var x in dict)
            result[x.Key] = x.Value;
    return result;
}
tvanfosson
  • 490,224
  • 93
  • 683
  • 780
orip
  • 66,082
  • 20
  • 111
  • 144
25

Try the following

static Dictionary<TKey, TValue>
    Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> enumerable)
{
    return enumerable.SelectMany(x => x).ToDictionary(x => x.Key, y => y.Value);
}
mtijn
  • 3,440
  • 2
  • 26
  • 54
JaredPar
  • 673,544
  • 139
  • 1,186
  • 1,421
22
Dictionary<String, String> allTables = new Dictionary<String, String>();
allTables = tables1.Union(tables2).ToDictionary(pair => pair.Key, pair => pair.Value);
ctrlalt313373
  • 3,466
  • 6
  • 34
  • 39
  • 1
    Just wondering - wouldn't just *Union* just work? ```foreach(var kvp in Message.GetAttachments().Union(mMessage.GetImages()))``` Using it in production code, if there are any downsides please let me know! :) – Mars Robertson Aug 02 '13 at 07:21
  • 2
    @Michal: Union will return an `IEnumerable>` where equality is defined by equality of key and value (there is an overload to allow for alternatives). This is fine for a foreach loop, where this is all that is necessary, but there are cases where you actually want the dictionary. – Timothy Oct 07 '16 at 18:15
20

I'm very late to the party and perhaps missing something, but if either there are no duplicate keys or, as the OP says, "In case of collision, it doesn't matter which value is saved to the dict as long as it's consistent," what's wrong with this one (merging D2 into D1)?

foreach (KeyValuePair<string,int> item in D2)
{
    D1[item.Key] = item.Value;
}

It seems simple enough, maybe too simple, I wonder if I'm missing something. This is what I'm using in some code where I know there are no duplicate keys. I'm still in testing, though, so I'd love to know now if I'm overlooking something, instead of finding out later.

idbrii
  • 9,440
  • 5
  • 50
  • 93
codingatty
  • 1,507
  • 1
  • 13
  • 27
  • 6
    One of the cleanest and most readable solutions imo and also avoids the ToList() that many others use. – 404 Mar 01 '18 at 10:46
  • The only thing wrong with this answer is that OP asked for a solution "best way to merge 2 **or more** dictionaries" but this solution handles merging two dictionaries. – idbrii May 17 '21 at 18:03
16

The following works for me. If there are duplicates, it will use dictA's value.

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> dictA, IDictionary<TKey, TValue> dictB)
    where TValue : class
{
    return dictA.Keys.Union(dictB.Keys).ToDictionary(k => k, k => dictA.ContainsKey(k) ? dictA[k] : dictB[k]);
}
Ethan Reesor
  • 1,851
  • 1
  • 21
  • 37
  • I had to remove 'where TValue : class' to use Guid as a value – om471987 Jan 25 '16 at 23:47
  • @om471987 Yes, Guid is a struct not a class, so that makes sense. I think originally I had some problem when I didn't add that clause. Don't remember why anymore. – Ethan Reesor Jan 26 '16 at 07:16
14

Here is a helper function I use:

using System.Collections.Generic;
namespace HelperMethods
{
    public static class MergeDictionaries
    {
        public static void Merge<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
        {
            if (second == null || first == null) return;
            foreach (var item in second) 
                if (!first.ContainsKey(item.Key)) 
                    first.Add(item.Key, item.Value);
        }
    }
}
Andrew Harry
  • 13,417
  • 16
  • 64
  • 101
  • 1
    There are a lot of great solutions listed here, but I rather like the simplicity of this one the most. Just my personal preference. – jason Oct 19 '12 at 15:24
  • 4
    `if(first == null)` then this logic is useless because `first` is not `ref` and is not returned. And it can't be `ref` because it's declared as an interface instance; you need to either remove the error-checking or declare it as a class instance or just return a new dictionary (with no extension method). – Grault Mar 15 '13 at 06:18
  • @Grault: The null checks are to prevent failure on invalid input. There's nothing preventing you from calling `Merge(null, null);` or `Dict b = null; b.Merge(null);` Reference type arguments can be null even if they are not `ref`. See [note on the "Passing an argument by reference" docs](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref). – idbrii May 17 '21 at 18:01
10

Option 1 : This depends on what you want to happen if you are sure that you don't have duplicate key in both dictionaries. than you could do:

var result = dictionary1.Union(dictionary2).ToDictionary(k => k.Key, v => v.Value)

Note : This will throw error if you get any duplicate keys in dictionaries.

Option 2 : If you can have duplicate key then you'll have to handle duplicate key with the using of where clause.

var result = dictionary1.Union(dictionary2.Where(k => !dictionary1.ContainsKey(k.Key))).ToDictionary(k => k.Key, v => v.Value)

Note : It will not get duplicate key. if there will be any duplicate key than it will get dictionary1's key.

Option 3 : If you want to use ToLookup. then you will get a lookup which can have multiple values per key. You could convert that lookup to a dictionary:

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());
7

How about adding a params overload?

Also, you should type them as IDictionary for maximum flexibility.

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<IDictionary<TKey, TValue>> dictionaries)
{
    // ...
}

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(params IDictionary<TKey, TValue>[] dictionaries)
{
    return Merge((IEnumerable<TKey, TValue>) dictionaries);
}
Bryan Watts
  • 42,403
  • 15
  • 78
  • 85
  • 4
    He's kind of adding to the other answers here by noting you can make the DictionaryExtensions class even nicer. Perhaps this question should become a wiki, or a class checked in to git... . – Chris Moschini Dec 13 '12 at 07:15
5

Based on the answers above, but adding a Func-parameter to let the caller handle the duplicates:

public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> dicts, 
                                                           Func<IGrouping<TKey, TValue>, TValue> resolveDuplicates)
{
    if (resolveDuplicates == null)
        resolveDuplicates = new Func<IGrouping<TKey, TValue>, TValue>(group => group.First());

    return dicts.SelectMany<Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>>(dict => dict)
                .ToLookup(pair => pair.Key, pair => pair.Value)
                .ToDictionary(group => group.Key, group => resolveDuplicates(group));
}
toong
  • 1,260
  • 12
  • 18
5

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.

  • Why Remove() and then Add() instead of using the [`Item[]` property](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.item?view=net-5.0)? Also , Dictionary [doesn't appear to have](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.add?view=net-5.0) an Add function that takes a KeyValuePair: "CS7036 There is no argument given that corresponds to the required formal parameter 'value' of 'Dictionary.Add(T1, T2)" And where does `AddOrUpdate` come from? – idbrii May 17 '21 at 17:56
4

The party's pretty much dead now, but here's an "improved" version of user166390 that made its way into my extension library. Apart from some details, I added a delegate to calculate the merged value.

/// <summary>
/// Merges a dictionary against an array of other dictionaries.
/// </summary>
/// <typeparam name="TResult">The type of the resulting dictionary.</typeparam>
/// <typeparam name="TKey">The type of the key in the resulting dictionary.</typeparam>
/// <typeparam name="TValue">The type of the value in the resulting dictionary.</typeparam>
/// <param name="source">The source dictionary.</param>
/// <param name="mergeBehavior">A delegate returning the merged value. (Parameters in order: The current key, The current value, The previous value)</param>
/// <param name="mergers">Dictionaries to merge against.</param>
/// <returns>The merged dictionary.</returns>
public static TResult MergeLeft<TResult, TKey, TValue>(
    this TResult source,
    Func<TKey, TValue, TValue, TValue> mergeBehavior,
    params IDictionary<TKey, TValue>[] mergers)
    where TResult : IDictionary<TKey, TValue>, new()
{
    var result = new TResult();
    var sources = new List<IDictionary<TKey, TValue>> { source }
        .Concat(mergers);

    foreach (var kv in sources.SelectMany(src => src))
    {
        TValue previousValue;
        result.TryGetValue(kv.Key, out previousValue);
        result[kv.Key] = mergeBehavior(kv.Key, kv.Value, previousValue);
    }

    return result;
}
gxtaillon
  • 940
  • 1
  • 17
  • 29
4

Note that if you use an extension method called 'Add', you get to use collection initializers to combine as many dictionaries as needed like this:

public static void Add<K, V>(this Dictionary<K, V> d, Dictionary<K, V> other) {
  foreach (var kvp in other)
  {
    if (!d.ContainsKey(kvp.Key))
    {
      d.Add(kvp.Key, kvp.Value);
    }
  }
}


var s0 = new Dictionary<string, string> {
  { "A", "X"}
};
var s1 = new Dictionary<string, string> {
  { "A", "X" },
  { "B", "Y" }
};
// Combine as many dictionaries and key pairs as needed
var a = new Dictionary<string, string> {
  s0, s1, s0, s1, s1, { "C", "Z" }
};
Andy
  • 3,232
  • 5
  • 31
  • 30
3

Simplified from use compared with my earlier answer with a bool default of non-destructive merge if existing or overwrite entirely if true rather than using an enum. It still suits my own needs without any fancier code ever being required:

using System.Collections.Generic;
using System.Linq;

public static partial class Extensions
{
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, bool overwrite = false)
    {
        source.ToList().ForEach(_ => {
            if (overwrite || !target.ContainsKey(_.Key))
                target[_.Key] = _.Value;
        });
    }
}
idbrii
  • 9,440
  • 5
  • 50
  • 93
mattjs
  • 81
  • 4
  • It seems unnecessary to use `.ToList().ForEach` instead of `foreach`. Why allocate the list? – idbrii May 17 '21 at 17:57
2

@Tim: Should be a comment, but comments don't allow for code editing.

Dictionary<string, string> t1 = new Dictionary<string, string>();
t1.Add("a", "aaa");
Dictionary<string, string> t2 = new Dictionary<string, string>();
t2.Add("b", "bee");
Dictionary<string, string> t3 = new Dictionary<string, string>();
t3.Add("c", "cee");
t3.Add("d", "dee");
t3.Add("b", "bee");
Dictionary<string, string> merged = t1.MergeLeft(t2, t2, t3);

Note: I applied the modification by @ANeves to the solution by @Andrew Orsich, so the MergeLeft looks like this now:

public static Dictionary<K, V> MergeLeft<K, V>(this Dictionary<K, V> me, params IDictionary<K, V>[] others)
    {
        var newMap = new Dictionary<K, V>(me, me.Comparer);
        foreach (IDictionary<K, V> src in
            (new List<IDictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }
keni
  • 1,554
  • 11
  • 17
  • Close to what I wrote myself. This, ofc, will only work for `Dictionary` types. Overloads could be added for other Dictionary types (`ConcurrentDictionary`, `ReadOnlyDictionary`, etc) I don't think the creation of a new list, and concat is necessary personally. I just iterated the params array first, then iterated each KVP of each dictionary. I don't see a draw back. – crush Jul 21 '15 at 23:34
  • You can use IDictionary instead of Dictionary – Mariusz Jamro Apr 18 '16 at 06:41
  • 1
    You would always be getting a `Dictionary` object even if you used the extension method on a `ConcurrentDictionary`. That could lead to hard to trace bugs. – Marcel May 14 '16 at 05:59
  • newMap is initialized with `me`, so you shouldn't need the Concat -- you're adding `me`'s values twice. – idbrii May 17 '21 at 18:34
2

I know this is an old question, but since we now have LINQ you can do it in a single line like this

Dictionary<T1,T2> merged;
Dictionary<T1,T2> mergee;
mergee.ToList().ForEach(kvp => merged.Add(kvp.Key, kvp.Value));

or

mergee.ToList().ForEach(kvp => merged.Append(kvp));
Cruces
  • 2,199
  • 1
  • 14
  • 40
  • Sorry for the downvote @Cruces, but your first example duplicates answer https://stackoverflow.com/a/6695211/704808 and your second example just keeps discarding the expanded IEnumerable> after appending each item from `mergee`. – weir Jul 06 '18 at 19:30
2

Got scared to see complex answers, being new to C#.

Here are some simple answers.
Merging d1, d2, and so on.. dictionaries and handle any overlapping keys ("b" in below examples):

Example 1

{
    // 2 dictionaries,  "b" key is common with different values

    var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
    var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };

    var result1 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
    // result1 is  a=10, b=21, c=30    That is, took the "b" value of the first dictionary

    var result2 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
    // result2 is  a=10, b=22, c=30    That is, took the "b" value of the last dictionary
}

Example 2

{
    // 3 dictionaries,  "b" key is common with different values

    var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
    var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };
    var d3 = new Dictionary<string, int>() { { "d", 40 }, { "b", 23 } };

    var result1 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
    // result1 is  a=10, b=21, c=30, d=40    That is, took the "b" value of the first dictionary

    var result2 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
    // result2 is  a=10, b=23, c=30, d=40    That is, took the "b" value of the last dictionary
}

For more complex scenarios, see other answers.
Hope that helped.

Manohar Reddy Poreddy
  • 16,412
  • 7
  • 111
  • 98
2
using System.Collections.Generic;
using System.Linq;

public static class DictionaryExtensions
{
    public enum MergeKind { SkipDuplicates, OverwriteDuplicates }
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, MergeKind kind = MergeKind.SkipDuplicates) =>
        source.ToList().ForEach(_ => { if (kind == MergeKind.OverwriteDuplicates || !target.ContainsKey(_.Key)) target[_.Key] = _.Value; });
}

You can either skip/ignore (default) or overwrite the duplicates: And Bob's your uncle provided you are not overly fussy about Linq performance but prefer instead concise maintainable code as I do: in which case you can remove the default MergeKind.SkipDuplicates to enforce a choice for the caller and make the developer cognisant of what the results will be!

mattjs
  • 81
  • 4
2

A version from @user166390 answer with an added IEqualityComparer parameter to allow for case insensitive key comparison.

    public static T MergeLeft<T, K, V>(this T me, params Dictionary<K, V>[] others)
        where T : Dictionary<K, V>, new()
    {
        return me.MergeLeft(me.Comparer, others);
    }

    public static T MergeLeft<T, K, V>(this T me, IEqualityComparer<K> comparer, params Dictionary<K, V>[] others)
        where T : Dictionary<K, V>, new()
    {
        T newMap = Activator.CreateInstance(typeof(T), new object[] { comparer }) as T;

        foreach (Dictionary<K, V> src in 
            (new List<Dictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }
gorillapower
  • 332
  • 4
  • 15
1

Merging using an extension method. It does not throw exception when there are duplicate keys, but replaces those keys with keys from the second dictionary.

internal static class DictionaryExtensions
{
    public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second)
    {
        if (first == null) throw new ArgumentNullException("first");
        if (second == null) throw new ArgumentNullException("second");

        var merged = new Dictionary<T1, T2>();
        first.ToList().ForEach(kv => merged[kv.Key] = kv.Value);
        second.ToList().ForEach(kv => merged[kv.Key] = kv.Value);

        return merged;
    }
}

Usage:

Dictionary<string, string> merged = first.Merge(second);
Andrew Mikhailov
  • 881
  • 9
  • 13
1
public static IDictionary<K, V> AddRange<K, V>(this IDictionary<K, V> one, IDictionary<K, V> two)
        {
            foreach (var kvp in two)
            {
                if (one.ContainsKey(kvp.Key))
                    one[kvp.Key] = two[kvp.Key];
                else
                    one.Add(kvp.Key, kvp.Value);
            }
            return one;
        }
mattylantz
  • 159
  • 1
  • 5
0

Merging using an EqualityComparer that maps items for comparison to a different value/type. Here we will map from KeyValuePair (item type when enumerating a dictionary) to Key.

public class MappedEqualityComparer<T,U> : EqualityComparer<T>
{
    Func<T,U> _map;

    public MappedEqualityComparer(Func<T,U> map)
    {
        _map = map;
    }

    public override bool Equals(T x, T y)
    {
        return EqualityComparer<U>.Default.Equals(_map(x), _map(y));
    }

    public override int GetHashCode(T obj)
    {
        return _map(obj).GetHashCode();
    }
}

Usage:

// if dictA and dictB are of type Dictionary<int,string>
var dict = dictA.Concat(dictB)
                .Distinct(new MappedEqualityComparer<KeyValuePair<int,string>,int>(item => item.Key))
                .ToDictionary(item => item.Key, item=> item.Value);
BSharp
  • 709
  • 7
  • 10
0

or :

public static IDictionary<TKey, TValue> Merge<TKey, TValue>( IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y)
    {
        return x
            .Except(x.Join(y, z => z.Key, z => z.Key, (a, b) => a))
            .Concat(y)
            .ToDictionary(z => z.Key, z => z.Value);
    }

the result is a union where for duplicate entries "y" wins.

jtroconisa
  • 99
  • 1
  • 3
0

I'd split @orip's simple and non-garbage creating solution to provide a in-place AddAll() in addition to Merge() to handle the simple case of adding one dictionary to another.

using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
    AddAll<TKey,TValue>(Dictionary<TKey, TValue> dest, Dictionary<TKey, TValue> source)
{
    foreach (var x in source)
        dest[x.Key] = x.Value;
}

public static Dictionary<TKey, TValue>
    Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
    var result = new Dictionary<TKey, TValue>();
    foreach (var dict in dictionaries)
        result.AddAll(dict);
    return result;
}
idbrii
  • 9,440
  • 5
  • 50
  • 93
-1
fromDic.ToList().ForEach(x =>
        {
            if (toDic.ContainsKey(x.Key))
                toDic.Remove(x.Key);
            toDic.Add(x);
        });
softwarevamp
  • 607
  • 8
  • 12