Combine two Dictionaries with LINQ

30,478

Solution 1

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)));

Solution 2

var d3 = d1.Concat(d2.Where(kvp => ! d1.ContainsKey(kvp.Key)))
           .ToDictionary(x => x.Key, x => x.Value);

This is working for me.

Solution 3

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 } }

Solution 4

Jon Skeet (as usual) has an extension method allowing you to do this: Can I specify my explicit type comparator inline?

Solution 5

Another solution using your own IEqualityComparer like in the answer of @bitxwise and @DaveShaw, but not using Except() which makes it a little simpler:

var d3 = d1.Concat(d2).Distinct(new MyComparer());
Share:
30,478

Related videos on Youtube

wageoghe
Author by

wageoghe

Software development primarily for mapping applications. #SOreadytohelp

Updated on July 09, 2022

Comments

  • wageoghe
    wageoghe almost 2 years

    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.

    • Michael Freidgeim
      Michael Freidgeim about 8 years
    • wageoghe
      wageoghe about 8 years
      This question is not a duplicate of that question. This question is asking how to combine two dictionaries, d1 and d2, such that the resulting dictionary has all items from d1 plus all items from d2 that are not already in d1. The other question is asking, and the answers explain how, to combine two dictionaries without any extra conditions.
  • wageoghe
    wageoghe over 13 years
    Thanks! That's a pretty cool approach as well as Mark's. I saw that I could use an IEqualityComparer, but I wondered if there was an even easier way.
  • wageoghe
    wageoghe over 13 years
    That is really cool! I probably won't do that now, but will file it away for later.
  • DaveShaw
    DaveShaw over 13 years
    There are loads and loads of Linq extensions. I would have used ExceptBy in this case come to think of it : code.google.com/p/morelinq/source/browse/trunk/MoreLinq/…
  • bitxwise
    bitxwise over 13 years
    Normally for quick things like KEY comparisons, LINQ is probably the way to go, but if you need something a bit more complicated (and need to reuse it), the IEqualityComparer could be better, especially if implemented as an extension method.