A few months back I posted about case-invariant string comparisons using the Equals method and the StringComparison enum. This approach made it a bit more efficient to compare strings without regards to their case since it wasn’t necessary to convert the strings to lower or upper case.
But what if you have a dictionary that is keyed by a string and you wish the lookup to be case insensitive? The following unit test demonstrates the problem, using a dictionary of city names and temperatures:
private Dictionary<String, Int32> GetDictionary() { Dictionary<String, Int32> dict = new Dictionary<String, Int32>() { {"New York", 42}, {"Boston", 35}, {"Atlanta", 58} }; return dict; } [TestMethod] public void CaseInsensitive_KeyNotFound_Test() { Dictionary<String, Int32> dict = GetDictionary(); Assert.IsFalse(dict.ContainsKey("new york")); }
As the test shows, searching the dictionary for the lower-case city of “new york” fails. If you ask the user to input a city name and they don’t enter it as mixed case, you’re out of luck.
A workaround is to store the cities in the dictionary as upper (or lower) case and always ensure you search by the same case. But that gets a bit messy.
Fortunately there’s a better way. One of the Dictionary<TKey, TValue> constructors takes an IEqualityComparer<TKey> that lets you specify how you would like to compare the key of the dictionary.
The following unit test demonstrates this:
[TestMethod] public void CaseInsensitive_KeyFound_Test() { Dictionary<String, Int32> dict = new Dictionary<String, Int32>(StringComparer.OrdinalIgnoreCase) { {"New York", 42}, {"Boston", 35}, {"Atlanta", 58} }; Assert.IsTrue(dict.ContainsKey("new york")); }
In this example, we pass in a StringComparer.OrdinalIgnoreCase parameter that tells the dictionary to perform a case-insensitive string comparison. This lets us find our New York entry regardless of case. Now we have a better chance of finding the city when the user searches for it.
This is a very handy technique that also works with HashSet<T>.
Hope this helps.