30

I wish to have the dictionary which uses an array of integers as keys, and if the integer array has the same value (even different object instance), they will be treated as the same key. How should I do it?

The following code does not work as b is different object instances.

 int[] a = new int[] { 1, 2, 3 };
 int[] b = new int[] { 1, 2, 3 };
 Dictionary<int[], string> dic = new Dictionary<int[], string>();
 dic.Add(a, "haha");
 string output = dic[b];
1

3 Answers 3

46

You can create an IEqualityComparer to define how the dictionary should compare items. If the ordering of items is relevant, then something like this should work:

public class MyEqualityComparer : IEqualityComparer<int[]>
{
    public bool Equals(int[] x, int[] y)
    {
        if (x.Length != y.Length)
        {
            return false;
        }
        for (int i = 0; i < x.Length; i++)
        {
            if (x[i] != y[i])
            {
                return false;
            }
        }
        return true;
    }

    public int GetHashCode(int[] obj)
    {
        int result = 17;
        for (int i = 0; i < obj.Length; i++)
        {
            unchecked
            {
                result = result * 23 + obj[i];
            }
        }
        return result;
    }
}

Then pass it in as you create the dictionary:

Dictionary<int[], string> dic
    = new Dictionary<int[], string>(new MyEqualityComparer());

Note: calculation of hash code obtained here: What is the best algorithm for an overridden System.Object.GetHashCode?

Sign up to request clarification or add additional context in comments.

6 Comments

Why there is a need for GetHashCode other than the Equal operator?
@william007 Because a Dictionary<,> maintains a hash table of its keys, and therefore it is necessary to have a GetHashCode that respects the new Equals. For the same reason, the IEqualityComparer<> interface requires you to do GetHashCode.
Why do you call it My EqualityComparer? The fact that it's yours is irrelevant. It should be called IntArrayEqualityComparer or something similar :)
Why can GetHashCode() not simply return obj.GetHashCode()?
@SimonHewitt because a hash code must follow the rule that if two objects return true for x.Equals(y) then x.GetHashCode() == y.GetHashCode() must also be true. Using obj.GetHashCode() will not fulfill that promise because you have a custom implementation of Equals you will be using for the comparisons so you will end up with x.Equals(y) == true and x.GetHashCode() != y.GetHashCode() which is illegal in a correct hashcode implementation..
|
5

Maybe you should consider using a Tuple

var myDictionary = new Dictionary<Tuple<int,int>, string>(); 
myDictionary.Add(new Tuple<int,int>(3, 3), "haha1"); 
myDictionary.Add(new Tuple<int,int>(5, 5), "haha2"); 

According to MSDN , Tuple objects Equals method will use the values of the two Tuple objects

3 Comments

Not scalable to arrays of differing lengths
My array was always of a fixed length, so this was the cleanest solution in my case. Thanks
@bkw1491 starting with C# 7 you can simplify this to var myDictionary = new Dictionary<(int,int), string>(); myDictionary.Add((5, 5), "haha2");
0

The easiest way if you don't care about actual hashing may just be to convert the array into a string. Adding a space to avoid numbers joining.

dic.Add(String.Join(" ",a), "haha");

3 Comments

dic.Add(String.Join("", new int[] {1, 2, 3}), "haha"); dic.Add(String.Join("", new int[] {12, 3}), "this fails");
the performance of this approach is not good enough in case using it for memorizing paths in algorithms such as DFS
In fact, it is twice slower than stackoverflow.com/a/14663233/8012407. However, all the solutions up to now are still significantly slower than Python.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.