一个整数数组作为字典的键

29
我希望得到一个使用整数数组作为键的字典,如果整数数组具有相同的值(即使是不同的对象实例),它们也将被视为相同的键。我应该怎么做?
以下代码不起作用,因为b是不同的对象实例。
 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
重复:http://stackoverflow.com/questions/3383534/dictionary-with-integer-array-as-a-key,这与`List<int>`有关。 - Nate-Wilkins
3个回答

45

您可以创建一个IEqualityComparer来定义字典如何比较项。 如果项的顺序很重要,那么像这样做应该可以:

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;
    }
}

然后在创建字典时将其传入:

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

注意:在这里获取哈希码的计算: 什么是重写System.Object.GetHashCode()最佳算法?

为什么需要GetHashCode而非Equal运算符? - william007
3
因为Dictionary<,>会维护一个其键的哈希表,所以需要有一个遵守新的Equals方法的GetHashCode方法。出于同样的原因,IEqualityComparer<>接口要求你实现GetHashCode方法。 - Jeppe Stig Nielsen
4
为什么要称它为**我的** EqualityComparer?它属于你并不重要。应该将其称为IntArrayEqualityComparer或类似的名称 :) - BartoszKP
为什么GetHashCode()不能简单地返回obj.GetHashCode()? - Simon Hewitt
1
@SimonHewitt 因为哈希码必须遵循这样的规则:如果两个对象对 x.Equals(y) 返回 true,则 x.GetHashCode() == y.GetHashCode() 也必须为 true。使用 obj.GetHashCode() 将无法实现该承诺,因为您将使用自定义的 Equals 实现进行比较,因此您最终会得到 x.Equals(y) == truex.GetHashCode() != y.GetHashCode(),这在正确的哈希码实现中是不合法的。 - Scott Chamberlain
使用数组作为字典的键,在 Python 中比 C# 快大约50-100倍。不幸的是,这在 Python 中是默认支持的。 - Hieu Le

5
也许您应该考虑使用元组。
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"); 

根据 MSDN ,元组对象的Equals方法将使用两个元组对象的值进行比较。

2
不适用于长度不同的数组。 - Paul Childs
1
我的数组长度总是固定的,所以这在我的情况下是最干净的解决方案。谢谢 - bkw1491
2
@bkw1491 从C# 7开始,您可以将其简化为var myDictionary = new Dictionary<(int,int), string>(); myDictionary.Add((5, 5), "haha2"); - null

0

如果您不关心实际哈希值,最简单的方法可能是将数组转换为字符串。添加一个空格以避免数字连接。

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

2
dic.Add(String.Join("", new int[] {1, 2, 3}), "哈哈"); dic.Add(String.Join("", new int[] {12, 3}), "这个失败了"); - Paul Childs
这种方法在记忆路径的算法(如DFS)中使用时性能不够好。 - Hieu Le
事实上,它比 https://dev59.com/P2Uq5IYBdhLWcg3wPuFQ#14663233 慢两倍。然而,到目前为止所有的解决方案仍然比 Python 慢得多。 - Hieu Le

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接