Question

I have two dictionaries, one contains the original data and the other contains the new data. I want to compare the two dictionaries and return a dictionaries and return a third that contains updates.

Dictionary<int, Dictionary<string, string>> OriginalDictionary = new Dictionary
{
    {1, new Dictionary<string, string> 
        {{"name", "adam"}, 
         {"age", "15"}
         {"occupation", "student"}},
    {2, new Dictionary<string, string> 
        {{"name", "bob"}, 
         {"age", "40"}
         {"occupation", "doctor"}},
    {3, new Dictionary<string, string> 
        {{"name", "cameron"}, 
         {"age", "32"}
         {"occupation", "teacher"}},
}

Dictionary<int, Dictionary<string, string>> NewDictionary = new Dictionary
{
    {1, new Dictionary<string, string> 
        {{"name", "adam"}, 
         {"age", "15"}
         {"occupation", "student"}},
    {2, new Dictionary<string, string> 
        {{"name", "bob"}, 
         {"age", "40"}
         {"occupation", "lawyer"}}, //this is where it's different
    {3, new Dictionary<string, string> 
        {{"name", "cameron"}, 
         {"age", "32"}
         {"occupation", "teacher"}},
}

I want to get a third dictionary that contains the updates. It can be eithere the whole first level, or breaking down into the second level. The below 2 examples will both work for me.

Dictionary<int, Dictionary<string, string>> UpdateDictionary1 = new Dictionary
{
    {2, new Dictionary<string, string> 
        {{"name", "bob"}, 
         {"age", "40"}
         {"occupation", "lawyer"}} //this is where it's different
}

Dictionary<int, Dictionary<string, string>> UpdateDictionary2 = new Dictionary
{
    {2, new Dictionary<string, string> 
        {{"occupation", "lawyer"}}
}

I have tried the answers from this post How to compare two Dictionaries in C#, but the results I got for UpdateDictionary still contains all the data from NewDictionary. UpdatesDictionary.Count == 3, which my expected output should be UpdatesDictionary.Count == 1. I tried the Where answer and the Except answer and they both weren't working as I want it to be.

UpdateDictionary = OriginalDictionary.Where(entry => NewDictionary[entry.Key] != entry.Value).ToDictionary(entry => entry.Key, entry => entry.Value);

UpdateDictionary = OriginalDictionary.Except(NewDictionary).ToDictionary(x => x.Key, x => x.Value);

Is there some other way I should approach this?

Thanks!

Was it helpful?

Solution

So first the easy part. Find the keys that were added or removed:

var addedKeys = NewDictionary.Keys.Except(OriginalDictionary.Keys);
var removedKeys = OriginalDictionary.Keys.Except(NewDictionary.Keys);

Next, to find the keys that had an edited dictionary we'll create an equality comparer for dictionaries, simply because trying to inline all of the possible ways that they can differ is going to be too much.

public class DictionaryComparer<TKey, TValue> :
    IEqualityComparer<Dictionary<TKey, TValue>>
{
    private IEqualityComparer<TValue> valueComparer;
    public DictionaryComparer(IEqualityComparer<TValue> valueComparer = null)
    {
        this.valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
    }
    public bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y)
    {
        if (x.Count != y.Count)
            return false;
        if (x.Keys.Except(y.Keys).Any())
            return false;
        if (y.Keys.Except(x.Keys).Any())
            return false;
        foreach (var pair in x)
            if (!valueComparer.Equals(pair.Value, y[pair.Key]))
                return false;
        return true;
    }

    public int GetHashCode(Dictionary<TKey, TValue> obj)
    {
        throw new NotImplementedException();
    }
}

Now that we have this, calling it is pretty straightforward:

var addedKeys = NewDictionary.Keys.Except(OriginalDictionary.Keys);
var removedKeys = OriginalDictionary.Keys.Except(NewDictionary.Keys);
var comparer = new DictionaryComparer<string, string>();
var editedValues = OriginalDictionary.Where(pair =>
    !comparer.Equals(pair.Value, NewDictionary[pair.Key]));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top