Case-less Dictionary keys

How to ignore the case of Dictionary keys when performing operations

Home DailyDrop

Daily Knowledge Drop

The Dictionary constructor can take a StringComparer parameter allowing for retrieving of keys from the dictionary while ignoring the case of the key. This removes the need to perform ToUpper and ToLower on the calls involving the key.


Without StringComparer

Without a StringComparer, the case of the key added to the dictionary, and the case of the key when performing a lookup, need to match:

Dictionary<string, int>? artistAlbum = new Dictionary<string, int>();

// Call made to .ToLower() to ensure all artist 
// names are in the same standard format
artistAlbum.Add("Foo Fighters".ToLower(), 10);
artistAlbum.Add("John Mayer".ToLower(), 8);

// check will only return true if using lower case values,
// or specifically calling ToLower
Console.WriteLine(artistAlbum.ContainsKey("Foo Fighters")); // false
Console.WriteLine(artistAlbum.ContainsKey("Foo Fighters".ToLower())); // true
Console.WriteLine(artistAlbum.ContainsKey("foo fighters")); // true

In this example, ToLower is called each time an item is added to the Dictionary. When performing a check to see if the Dictionary contains a key, a match will only be found if the supplied value is all lower case, or if ToLower is specifically called again. This ensure that the keys are always stored, and then looked-up in a consistent format - lower case in this example.

However, all the ToLower (or ToUpper) calls do have a performance impact, and additionally they have to manually be added everywhere the Dictionary is used. A simpler and better approach is to use a StringComparer.


With StringComparer

Using the StringComparer technique is as simple as passing a value into the Dictionary constructor:

Dictionary<string, int>? artistAlbum = 
        new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

artistAlbum.Add("Foo Fighters", 10);
artistAlbum.Add("John Mayer", 8);

Console.WriteLine(artistAlbum.ContainsKey("Foo Fighters")); // true
Console.WriteLine(artistAlbum.ContainsKey("Foo fighters")); // true
Console.WriteLine(artistAlbum.ContainsKey("foo fighters")); // true

With StringComparer.OrdinalIgnoreCase is supplied to constructor, ToLower is no longer required when adding or checking the existence of a key. The case is now ignored when doing the comparison - this results in cleaner code, and better overall performance.


Notes

If the Dictionary could contain keys of various cases (maybe based on user input) then StringComparer should be used over ToLower or ToUpper. There is no overhead to using this approach, and is actually cleaner and more performant.


References

Pass in StringComparer to Dictionary

Daily Drop 242: 25-01-2023

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net dictionary comparer ignorecase