Search code examples
c#arraysdictionarycontains

C# Check if dictionary contains key which is a reference type


If I have a Dictionary<int[], int>, which contains 2 entries

{1, 2, 3} , 1 and
{4, 5, 6} , 2

How do I check whether the dictionary contains the key {1, 2, 3}? If i do:

if (dictionary.ContainsKey(new int[] {1,2,3})
{
  // do things
}

It will not return the correct result as the created array is different from the key array. I know you can override the Equals method for a custom class, but is there another way to check if a dictionary which has an array as the key, contains an entry whose key array has the same values within it as the comparison array?


Solution

  • Well, arrays are compared by reference so we have

    int[] a = new int[] {1, 2, 3};
    
    int[] b = new int[] {1, 2, 3}; // same content, different reference
    
    // Prints "No"
    Console.WriteLine(a.Equals(b) ? "Yes" : "No");
    
    Dictionary<int[], string> dict = new Dictionary<int[], string>() {{
      a, "Some Value"}};
    
    // Prints "Not Found"
    Console.WriteLine(dict.TryGetValue(b, out var value) ? value : "Not Found");
    

    So we have to explain .Net how to compare arrays; we can do it with a comparer:

    public class SequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>> {
      public bool Equals(IEnumerable<T> x, IEnumerable<T> y) {
        if (ReferenceEquals(x, y))
          return true;
        else if (null == x || null == y)
          return false;
    
        return Enumerable.SequenceEqual(x, y, EqualityComparer<T>.Default); 
      }
    
      public int GetHashCode(IEnumerable<T> obj) =>
        obj == null ? 0 : obj.FirstOrDefault()?.GetHashCode() ?? 0;
    }
    

    And we should declare the dictionary while mentioning the comparer:

    Dictionary<int[], string> dict = 
      new Dictionary<int[], string>(new SequenceEqualityComparer<int>()) {
        {a, "Some Value"}};
    

    Now we can do business as usual:

    // Returns "Some Value" 
    Console.WriteLine(dict[b]);