问题
In the following code, I am trying to check if two strings are anagrams. To that, I am counting the characters in the two strings in a hash table by storing the unique characters as key and its count in the string as values. At the end, when I go to check if each of the character have the same count, I get a false output, see the line marked as "PROBLEM" in the code. But when I convert the values in that line to string, the code works fine. What am I missing?
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;
}
}
}
回答1:
The Hashtable class is not generic; it just contains Objects, not a specific type.
When you do this:
if (uniqueChars1[key] != uniqueChars2[key])
the compile-time type of uniqueChars[key] is Object, not Int32. So you're using the Object implementation of the inequality operator, which just compares references. Since Int32 is a value type, and the indexer returns an object, the value is boxed; and since you're boxing two values, you get two distinct object instances, so reference equality always returns false.
You have several options:
- use a
Dictionary<char, int>, which is the generic equivalent ofHashtable cast the values to
intbefore comparison:if ((int)uniqueChars1[key] != (int)uniqueChars2[key])use the
Equalsmethod to compare values:if (!uniqueChars1[key].Equals(uniqueChars2[key]))
Unless you're still using .NET 1.x, I strongly advise you to use generic collections everywhere you can. They're safer, more intuitive, and have better performance for value types.
Side note (unrelated to your problem): you don't need to pass the Hashtable by reference to AddToHashTable; the code would work exactly the same way without the ref modifier, because Hashtable is a reference type, so it's always a reference that is passed anyway. The ref modifier would only be useful if you were assigning something else to the uniqueChars parameter, or if you were passing a value type and mutating its state (which is usually consider a bad thing). I suggest you read Jon Skeet's great article about value types, reference types, and parameter passing.
回答2:
Your problem comes from the fact that != will compare reference equality on two objects. uniqueCharsX[key] returns a int boxed inside a object, while you have the same int being returned from both hashtables the box they are being returned in is not the same box so you get a incorrect value.
Either use a strongly typed Dictionary<char, int> instead of a hashtable or use !uniqueChars1[key].Equals(uniqueChars2[key]) instead of uniqueChars1[key] != uniqueChars2[key] which will unbox the int and compare on the value instead (I highly recommend you use the Dictionary.)
来源:https://stackoverflow.com/questions/27882847/why-is-value-comparison-in-hashtable-returning-false-even-when-the-values-are-th