Home > Back-end >  Comparing two dictionaries (Key, value) and return Keys that doesn't have same value
Comparing two dictionaries (Key, value) and return Keys that doesn't have same value

Time:12-15

I'm bit new to c# and want to identify keys that doesn't have same value while comparing two dictionaries.

The dictionary I have is of dict => KeyValuePair<string, string>. And I have two dictionaries like -

dict1 => {"a":"False","b":"amazonaws.com","c":"True"}
dict2 => {"a":"True","b":"amazonaws.com","c":"False"}

I want to compare both dictionaries and return a variable which will have Keys ["a", "c"] as for the above example, those keys have different value.

Currently the logic I have written will only differentiate keys that's not there in the other dictionary.

Dictionary dictExcept = null;
foreach (IDictionary kvp in dict1.Cast<object>().Where(kvp => !dict2.Contains(kvp)))
    {
        dictExcept.Add(kvp.Keys, kvp.Values);
    }
return dictExcept ;

CodePudding user response:

You can try using TryGetValue:

using System.Linq;

...

var dictExcept = dict1
  .Where(pair => dict2.TryGetValue(pair.Key, out var value) && 
                 pair.Value != value)
  .ToDictionary(pair => pair.Key, 
                pair => (first: pair.Value, second: dict2[pair.Key]));

Here we for each key value pair from dict1 try to get corresponding value from dict2:

// dict2 has pair.Key it corresponds to value...
dict2.TryGetValue(pair.Key, out var value) && 
// however value from dict2 != value from dict1
pair.Value != value

The very same idea if you prefer to use foreach (no Linq solution):

var dictExcept = new Dictionary<string, (string first, string second)>();

foreach (var pair in dict1)
  if (dict2.TryGetValue(pair.Key, out var value) && value != pair.Value)
    dictExcept.Add(pair.Key, (pair.Value, value)); 

Demo: (fiddle)

  var dict1 = new Dictionary<string, string> { 
    { "a", "False" }, { "b", "False" }, { "c", "True" }, { "d", "dict1 only" } };

  var dict2 = new Dictionary<string, string> { 
    { "a", "False" }, { "b", "True" }, { "c", "False" }, { "e", "dict2 only" } };

  var dictExcept = dict1
    .Where(pair => dict2.TryGetValue(pair.Key, out var value) &&
                   pair.Value != value)
    .ToDictionary(pair => pair.Key,
                  pair => (first: pair.Value, second: dict2[pair.Key]));

  string report = string.Join(Environment.NewLine, dictExcept
    .Select(pair => $"Key: {pair.Key}; Values: {pair.Value}"));

  Console.Write(report);

Outcome:

Key: b; Values: (False, True)
Key: c; Values: (True, False)

CodePudding user response:

Providing the simplest answer because of your comment:

Both the dictionaries will have same keys, just that we need to identify keys that has different values

Working under that assumption that you don't need to account for missing keys, you can simply iterate over all the keys of one of the dictionaries, and compare the values found under that key.

var keysWithDifferentValues = new List<string>();

foreach (var kvp in dict1)
{
    if(!kvp.Value.Equals(dict2[kvp.Key]))
        keysWithDifferentValues.Add(kvp.Key);
}

This can be simplified using LINQ:

var keysWithDifferentValues = 
      dict1
        .Where(kvp => !kvp.Value.Equals(dict2[kvp.Key]))  
        .Select(kvp => kvp.Key)
        .ToList();                                  

CodePudding user response:

Since you have a dictionary named dictExcept, what about using Expect to do the job for you?

Produces the set difference of two sequences.

source

And in your case:

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

public class Program
{
    static void Main(string[] args)
    {
        var a = new Dictionary<string, string>{{"a", "False"}, {"b", "False"}, {"c", "True"}};
        var b = new Dictionary<string, string>{{"a", "False"}, {"b", "True"}, {"c", "False"}};
        
        var c = a.Except(b).Select(x => x.Key);
        c.Dump();
    }
}

output

[ b, c ]

Try it online!

More examples with different cases:

static void Main(string[] args)
{
    var a = new Dictionary<string, string>{{"a", "False"}, {"b", "False"}, {"c", "True"}};
    var b = new Dictionary<string, string>{{"a", "False"}, {"b", "True"}, {"c", "False"}};
    
    var c = a.Except(b).Select(x => x.Key);
    // c is [ b ,c ]
    
    a.Add("d", "foo");
    
    var d = a.Except(b).Select(x => x.Key);
    // d is [ b, c, d ]
    
    b.Add("e", "foo");
    
    var e = a.Except(b).Select(x => x.Key);
    // e is still [ b, c, d ]
    
    var e2 = (a.Except(b)).Union(b.Except(a)).Select(x => x.Key).Distinct();
    // e is [ b, c, d, e ]
}

Try it Online!

  • Related