1

I have two dictionaries and I want to compare them. I want to ignore case and only return false if they have different values. Here is my code.

var dic1 = new Dictionary<String, String>(StringComparer.CurrentCultureIgnoreCase);
            dic1.Add("Key 2", "Value 2");
            dic1.Add("Key 1", "Value 1"); 


            var dic2 = new Dictionary<String, String>(StringComparer.CurrentCultureIgnoreCase);
            dic2.Add("Key 1", "Value 1");
            dic2.Add("Key 2", "Value 2");

            var areEqual = dic1.OrderBy(r => r.Key).SequenceEqual(dic2.OrderBy(r => r.Key));

            Console.WriteLine(areEqual);

As you can see I am using the SequenceEqual method of the dictionary class to compare the two dictionaries. I have ordered them by key so that the result is not false if the key position is different. The problem I cant seem to figure out is how to ignore the case in key and values and return false only if values are different. In my case value 1 and VALUE 1 are both equal and the result should be true. That is not my case here.

Afraz Ali
  • 2,672
  • 2
  • 27
  • 47

4 Answers4

2

You should really check if the lengths are equal and if the two dictionaries have the same keys. Once you get past this part, you can use the following snippet:

var dic1 = new Dictionary<String, String>();
dic1.Add("Key 2", "Value 2");
dic1.Add("Key 1", "Value 1");

var dic2 = new Dictionary<String, String>();
dic2.Add("Key 1", "Value 1");
dic2.Add("Key 2", "Value 2");

bool areEqual = dic1.OrderBy(x => x.Key).Select(x => x.Value.ToUpperInvariant())
     .SequenceEqual(dic2.OrderBy(x => x.Key).Select(x => x.Value.ToUpperInvariant()));

Console.WriteLine(areEqual);
Andrei V
  • 7,306
  • 6
  • 44
  • 64
  • It's not going to work. See: http://stackoverflow.com/questions/3550213/in-c-sharp-what-is-the-difference-between-toupper-and-toupperinvariant – dzendras Sep 27 '13 at 07:04
  • @dzendras It is going to work, just not in particular cases, like Turkey. Thanks for the suggestion, I edited and replaced `ToUpper` with `ToUpperInveriant`. – Andrei V Sep 27 '13 at 07:08
  • Anyway ToUpper is not a way to go anyway. Each ToUpper creates a new instance of a string. Imagine what happens when the dictionary contains 10 millions of elements. You should use an overload with comparer (as pointed out in other answers). Yours is wrong. – dzendras Sep 27 '13 at 08:14
  • 1
    I'm sorry, but you seem to not have a clear grasp on semantics. What you can say is that my answer does not scale (i.e. it is not efficient). You can't really use "wrong" here... – Andrei V Sep 27 '13 at 08:21
  • Whatever... The answer should not be promoted anyway. Get on with it. – dzendras Sep 27 '13 at 09:39
2

Order by the key, select the value and use the overload of SequenceEqual with StringComparer.OrdinalIgnoreCase:

 bool areEqual = dic1.OrderBy(x => x.Key).Select(kv => kv.Value)
  .SequenceEqual(dic2.OrderBy(x => x.Key).Select(kv => kv.Value), StringComparer.OrdinalIgnoreCase);

These enforce a byte-by-byte comparison similar to strcmp that not only avoids bugs from linguistic interpretation of essentially symbolic strings, but provides better performance.

http://msdn.microsoft.com/en-us/library/ms973919.aspx

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Thanks Tim I was using my own custom comparer but like your solution better so marked as answer. Thanks! – Afraz Ali Sep 27 '13 at 10:36
  • @AfrazAli: _"I have ordered them by key so that the result is not false if the key position is different."_ Do you need to take the key into account or not? You can use `dic1.Values` directly to compare only the values. So maybe it's better to use `dic1.Values.OrderBy(v => v).SequenceEqual(dic2.Values...` – Tim Schmelter Sep 27 '13 at 10:44
  • Yes Tim I want to comapre the keys as well. Your solution works perfectly according to my requirements. Thank! – Afraz Ali Sep 30 '13 at 05:27
1

Ended up using custom comparer to compare the values. Here is the code.

class Program
    {
        static void Main(string[] args)
        {
            var dic1 = new Dictionary<String, String>();
            dic1.Add("Key 2", "Value 2");
            dic1.Add("Key 1", "Value 1"); 


            var dic2 = new Dictionary<String, String>();
            dic2.Add("Key 1", "Value 1");
            dic2.Add("Key 2", "Value 2");

            var areEqual = dic1.OrderBy(r => r.Key).SequenceEqual(dic2.OrderBy(r => r.Key), new ProductComparer());

            Console.WriteLine(areEqual);

            Console.ReadLine();
        }
    }



    internal class ProductComparer : IEqualityComparer<KeyValuePair<string, string>>
    {
        public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
        {
            Boolean areEqual = (String.Compare(x.Key, y.Key, StringComparison.OrdinalIgnoreCase) == 0) && (String.Compare(x.Value, y.Value, StringComparison.OrdinalIgnoreCase) == 0);
            return areEqual;
        }

        public int GetHashCode(KeyValuePair<string, string> obj)
        {
            return obj.GetHashCode();
        }
    }
Afraz Ali
  • 2,672
  • 2
  • 27
  • 47
0

Firstly, check the lengths - if they aren't equal then return false.

Next iterate over each member and compare the values (assuming the have the same order). You can also do this by iterating over the first dictionary and checking to see if each element is in the second dictionary. As soon as it is not, break from the loop or return false.

ddoor
  • 5,819
  • 9
  • 34
  • 41
  • I want to ignore manually comparing the dictionaries and want to use the overload of SequenceEqual method for the moment. – Afraz Ali Sep 27 '13 at 06:51