175

If I have a Dictionary<String,...> is it possible to make methods like ContainsKey case-insensitive?

This seemed related, but I didn't understand it properly: c# Dictionary: making the Key case-insensitive through declarations

Community
  • 1
  • 1
Mr. Boy
  • 52,885
  • 84
  • 282
  • 517
  • 2
    Possible duplicate of [Case insensitive access for generic dictionary](http://stackoverflow.com/questions/13230414/case-insensitive-access-for-generic-dictionary) – Michael Freidgeim May 12 '16 at 07:33
  • That question is related, but not quite a duplicate of this one. That one gets into how to deal with an existing dictionary. I'm starting with new code, so the answers here are better suited. – goodeye Feb 27 '19 at 00:00

5 Answers5

349

This seemed related, but I didn't understand it properly: c# Dictionary: making the Key case-insensitive through declarations

It is indeed related. The solution is to tell the dictionary instance not to use the standard string compare method (which is case sensitive) but rather to use a case insensitive one. This is done using the appropriate constructor:

var dict = new Dictionary<string, YourClass>(
        StringComparer.InvariantCultureIgnoreCase);

The constructor expects an IEqualityComparer which tells the dictionary how to compare keys.

StringComparer.InvariantCultureIgnoreCase gives you an IEqualityComparer instance which compares strings in a case-insensitive manner.

Konrad Rudolph
  • 482,603
  • 120
  • 884
  • 1,141
  • 11
    Possible, the StringComparison.OrdinalIgnoreCase comparer faster than culture-based: http://stackoverflow.com/questions/492799/difference-between-invariantculture-and-ordinal-string-comparison – Manushin Igor Mar 30 '15 at 12:03
  • How do I do it if I am not creating a dictionary but trying to use ContainsKey() for a case insensitive key match on an existing dictionary that I get as a part of an object? – Shridhar R Kulkarni Jun 22 '18 at 09:41
  • 1
    @ShridharRKulkarni You fundamentally can't (efficiently). The comparison logic is a core part of the internal dictionary data structure. To allow this, the container would have to maintain multiple indices for its data, and dictionaries don't do this. – Konrad Rudolph Jun 22 '18 at 10:53
24
var myDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
myDic.Add("HeLlo", "hi");

if (myDic.ContainsKey("hello"))
    Console.WriteLine(myDic["hello"]);
RBT
  • 18,275
  • 13
  • 127
  • 181
Steve
  • 19,825
  • 5
  • 37
  • 61
16

There are few chances where your deal with dictionary which is pulled from 3rd party or external dll. Using linq

YourDictionary.Any(i => i.KeyName.ToLower().Contains("yourstring")))
Soviut
  • 79,529
  • 41
  • 166
  • 227
Kurkula
  • 6,673
  • 23
  • 99
  • 170
  • 3
    This works great. A word of caution though, if you change `Any` to `SingleOrDefault` you will not get `null` back if it doesn't exist, instead you will get a keyvaluepair with both key and value set to `null`! – NibblyPig Mar 02 '17 at 14:10
  • 2
    `Contains` Seems like a very specific use-case to something you were working on at the time. As a more generic helpful answer, I think `Equals` is better. And on that same note, instead of duplicating a string with `ToLower()`, It would be even better to use `StringComparison.xxxCase`. – Suamere Feb 06 '18 at 17:37
  • 1
    I am so tempted downvote this. Word of caution, if you are the owner of the dictionary this is most certainly not the way to do it. Only use this approach if you dont know how the dictionary was instantiated. Even then, for exact match of string (not just part match), use `dict.Keys.Contains("bla", appropriate comparer)` LINQ overload for ease of use. – nawfal Jul 23 '19 at 11:26
8

If you have no control in the instance creation, let say your object is desterilized from json etc, you can create a wrapper class that inherits from dictionary class.

public class CaseInSensitiveDictionary<TValue> : Dictionary<string, TValue>
{
    public CaseInSensitiveDictionary() : base(StringComparer.OrdinalIgnoreCase){}
}
A.G.
  • 95
  • 1
  • 6
2

I just ran into the same kind of trouble where I needed a caseINsensitive dictionary in a ASP.NET Core controller.

I wrote an extension method which does the trick. Maybe this can be helpful for others as well...

public static IDictionary<string, TValue> ConvertToCaseInSensitive<TValue>(this IDictionary<string, TValue> dictionary)
{
    var resultDictionary = new Dictionary<string, TValue>(StringComparer.InvariantCultureIgnoreCase);
    foreach (var (key, value) in dictionary)
    {
        resultDictionary.Add(key, value);
    }

    dictionary = resultDictionary;
    return dictionary;
}

To use the extension method:

myDictionary.ConvertToCaseInSensitive();

Then get a value from the dictionary with:

myDictionary.ContainsKey("TheKeyWhichIsNotCaseSensitiveAnymore!");
Ferry Jongmans
  • 565
  • 2
  • 8
  • 20