My question has been flagged as a possible duplicate of this question: How to combine two dictionaries without looping?
I believe my question is different because I am asking how to combine two dictionaries in a particular way: I want all items from Dictionary1 plus all items from Dictionary2 that are not in (ie the key does not exist) in Dictionary1.
I have two dictionaries like this:
var d1 = new Dictionary<string,object>();
var d2 = new Dictionary<string,object>();
d1["a"] = 1;
d1["b"] = 2;
d1["c"] = 3;
d2["a"] = 11;
d2["e"] = 12;
d2["c"] = 13;
I would like to combine them into a new Dictionary (technically, it does not have to be a dictionary, it could just be a sequence of KeyValuePairs
) such that the output contains all of the KeyValuePairs
from d1 and only the KeyValuePairs from d2
whose Key does not appear in d1
.
Conceptually:
var d3 = d1.Concat(d2.Except(d1))
But that is giving me all of the elements from d1 and d2.
Seems like it should be obvious, but I must be missing something.
We can use LINQ to merge any number of dictionaries in C#. The following code example shows how to implement this. If any of the keys gets repeated in any dictionary, the above code throws an ArgumentException. To handle this, the idea is to group elements based on the key before converting it to a dictionary.
When you use Except
by default it uses the default equality comparer, which for the KeyValuePair
type compares both the keys and the values. You could this approach instead:
var d3 = d1.Concat(d2.Where(kvp => !d1.ContainsKey(kvp.Key)));
var d3 = d1.Concat(d2.Where(kvp => ! d1.ContainsKey(kvp.Key))) .ToDictionary(x => x.Key, x => x.Value);
This is working for me.
Well I don't know if it's a new feature in LinQ, but that's exactly what .Union()
does :
var d3 = d1.Union(d2);
Of course with Dictionaries you'll have to give a custom equality comparer to match only the keys :
class KeyValuePairComparer<TKey, TValue> : IEqualityComparer<KeyValuePair<TKey, TValue>>
{
public bool Equals(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y)
{
return x.Key.Equals(y.Key);
}
public int GetHashCode(KeyValuePair<TKey, TValue> x)
{
return x.GetHashCode();
}
}
and then :
var d3 = d1.Union(d2, new KeyValuePairComparer<string, object>());
With your example, the output would be (tested in C# interactive) :
> d1.Union(d2, new KeyValuePairComparer<string, object>())
UnionIterator { { "a", 1 }, { "b", 2 }, { "c", 3 }, { "e", 12 } }
Note the difference :
> d2.Union(d1, new KeyValuePairComparer<string, object>())
UnionIterator { { "a", 11 }, { "e", 12 }, { "c", 13 }, { "b", 2 } }
Jon Skeet (as usual) has an extension method allowing you to do this: Can I specify my explicit type comparator inline?
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