C# – Merge two dictionaries in-place

When you merge two dictionaries, you can either merge them in-place, or create a new dictionary and copy the values over to it.

The following extension method does an in-place merge of two dictionaries. It puts items from the right dictionary into the left dictionary. When duplicate keys exist, it’s keeping the value from the left (instead of throwing an exception, or keeping the value from the right).

public static class DictUtils { public static Dictionary<Key, Value> MergeInPlace<Key, Value>(this Dictionary<Key, Value> left, Dictionary<Key, Value> right) { if (left == null) { throw new ArgumentNullException("Can't merge into a null dictionary"); } else if (right == null) { return left; } foreach (var kvp in right) { if (!left.ContainsKey(kvp.Key)) { left.Add(kvp.Key, kvp.Value); } } return left; } }

Note: Even though this is doing an in-place merge, it’s returning a dictionary. This is so you can use this in a fluent manner, for example: left.MergeInPlace(dict1).MergeInPlace(dict2).Count().

Unit tests for MergeInPlace()

Here are unit tests that exercise all the behavior in the MergeInPlace() method.

[TestClass()] public class DictUtilsTests { [TestMethod()] public void MergeInPlaceTest_WhenLeftNull_ThrowsNullArgument() { //arrange Dictionary<string, string> left = null; var right = new Dictionary<string, string>(); //act & assert Assert.ThrowsException<ArgumentNullException>(() => left.MergeInPlace(right)); } [TestMethod()] public void MergeInPlaceTest_WhenRightNull_ReturnsLeft() { //arrange var left = new Dictionary<string, string>(); Dictionary<string, string> right = null; //act var merged = left.MergeInPlace(right); //assert Assert.AreSame(left, merged); } [TestMethod()] public void MergeInPlaceTest_WhenItemInRight_MergesIntoLeft() { //arrange var testKey = "TEST"; var testValue = "1"; var left = new Dictionary<string, string>(); var right = new Dictionary<string, string>() { [testKey] = testValue }; //act left.MergeInPlace(right); //assert Assert.AreEqual(testValue, left[testKey]); } [TestMethod()] public void MergeInPlaceTest_WhenItemInLeft_StillInLeft() { //arrange var testKey = "TEST"; var testValue = "1"; var left = new Dictionary<string, string>() { [testKey] = testValue }; var right = new Dictionary<string, string>(); //act left.MergeInPlace(right); //assert Assert.AreEqual(testValue, left[testKey]); } [TestMethod()] public void MergeInPlaceTest_ItemsInLeftAndRight_PutsAllInLeft() { //arrange var leftTestKey = "TEST"; var leftTestValue = "1"; var left = new Dictionary<string, string>() { [leftTestKey] = leftTestValue }; var rightTestKey = "TEST2"; var rightTestValue = "2"; var right = new Dictionary<string, string>() { [rightTestKey] = rightTestValue }; var expected = new Dictionary<string, string>() { [leftTestKey] = leftTestValue, [rightTestKey] = rightTestValue }; //act left.MergeInPlace(right); //assert CollectionAssert.AreEqual(expected, left); } [TestMethod()] public void MergeInPlaceTest_WhenKeyInBothLeftAndRight_TakesTheValueFromLeft() { //arrange var testKey = "TEST"; var leftTestValue = "1"; var left = new Dictionary<string, string>() { [testKey] = leftTestValue }; var rightTestValue = "2"; var right = new Dictionary<string, string>() { [testKey] = rightTestValue }; //act left.MergeInPlace(right); //assert Assert.AreEqual(leftTestValue, left[testKey]); } }

Why not use Linq Union() or Concat()?

You might be wondering why you’d need to write your own merge method, instead of using the Linq Union() / Concat() methods.

The reason is because they can’t handle duplicate keys.

For example, let’s say I have two dictionaries that have the same key “TEST”.

var testKey = "TEST"; var testValueLeft = "1"; var testValueRight = "2"; var left = new Dictionary<string, string>() { [testKey] = testValueLeft }; var right = new Dictionary<string, string>() { [testKey] = testValueRight }; var merged = left.Union(right).ToDictionary(t => t.Key, t => t.Value);

This throws the following exception:

System.ArgumentException: An item with the same key has already been added

In the MergeInPlace() method I showed in this article, when the key exists in both dictionaries, it takes the value from the left. Because you’re writing your own merging logic, you can make it handle duplicates however you want.

With the Linq methods, they simply don’t handle duplicate keys at all.

Leave a Comment