为什么即使值相同,哈希表中的值比较也会返回 false?

Why is value comparison in hashtable returning false even when the values are the same?

在下面的代码中,我试图检查两个字符串是否是变位词。为此,我通过将唯一字符存储为键并将其在字符串中的计数存储为值来计算散列 table 中两个字符串中的字符。最后,当我去检查每个字符是否具有相同的计数时,我得到一个错误的输出,请参阅代码中标记为 "PROBLEM" 的行。但是当我将该行中的值转换为字符串时,代码工作正常。我错过了什么?

    static bool AreAnagrams(string input1, string input2)
    {
        Hashtable uniqueChars1 = new Hashtable();
        Hashtable uniqueChars2 = new Hashtable();

        // Go through first string and create a hash table of characters 
        AddToHashTable(input1, ref uniqueChars1);
        // Go through second string and create a second hash table of characters
        AddToHashTable(input2, ref uniqueChars2);

        // For each unique character, if the count from both hash tables are the same, they are anagrams
        if (uniqueChars1.Keys.Count != uniqueChars2.Keys.Count)
        {
            return false;
        }
        else
        {
            foreach (object key in uniqueChars1.Keys)
            {
                if (uniqueChars1[key] != uniqueChars2[key]) // ***PROBLEM HERE***
                {
                    return false;
                }
            }
        }
        return true;
    }

    static void AddToHashTable(string input, ref Hashtable uniqueChars)
    {
        foreach (char c in input)
        {

            if (!uniqueChars.ContainsKey(c))
            {
                uniqueChars.Add(c, 1);
            }
            else
            {
                int charCount = Convert.ToInt32(uniqueChars[c]);
                charCount++;
                uniqueChars[c] = charCount;
            }
        }
    }

Hashtable class 不是通用的;它只包含 Objects,而不是特定类型。

当你这样做时:

if (uniqueChars1[key] != uniqueChars2[key])

uniqueChars[key] 的编译时类型是 Object,而不是 Int32。因此,您使用的是不等式运算符的 Object 实现,它只是比较引用。由于Int32是值类型,索引器returns是对象,所以值为boxed;因为你装箱了两个值,你得到了两个不同的对象实例,所以引用相等总是 returns false.

您有多种选择:

  • 使用 Dictionary<char, int>,它是 Hashtable
  • 的通用等价物
  • 在比较之前将值转换为 int

    if ((int)uniqueChars1[key] != (int)uniqueChars2[key])
    
  • 使用Equals方法比较值:

    if (!uniqueChars1[key].Equals(uniqueChars2[key]))
    

除非您仍在使用 .NET 1.x,否则我强烈建议您尽可能使用泛型集合。它们更安全、更直观,并且对值类型具有更好的性能。


旁注(与您的问题无关):您不需要通过引用 AddToHashTable 来传递 Hashtable;如果没有 ref 修饰符,代码将以完全相同的方式工作,因为 Hashtable 是引用类型,所以它始终是传递的引用。 ref 修饰符仅在您将其他内容分配给 uniqueChars 参数时才有用,或者如果您正在传递值类型并改变其状态(这通常被认为是一件坏事)。我建议你阅读 Jon Skeet's great article about value types, reference types, and parameter passing.

您的问题来自于 != 将比较两个对象的引用相等性这一事实。 uniqueCharsX[key] returns 装箱在一个对象中的 int,虽然从两个哈希表返回了相同的 int,但返回它们的框不是同一个框,因此您得到了不正确的值。

要么使用强类型 Dictionary<char, int> 而不是哈希表,要么使用 !uniqueChars1[key].Equals(uniqueChars2[key]) 而不是 uniqueChars1[key] != uniqueChars2[key] 这将取消装箱 int 并比较值(我强烈建议您使用词典。)