Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Case insensitive access for generic dictionary

I have an application that use managed dlls. One of those dlls return a generic dictionary:

Dictionary<string, int> MyDictionary;   

The dictionary contains keys with upper and lower case.

On another side I am getting a list of potential keys (string) however I cannot guarantee the case. I am trying to get the value in the dictionary using the keys. But of course the following will fail since I have a case mismatch:

bool Success = MyDictionary.TryGetValue( MyIndex, out TheValue );   

I was hoping the TryGetValue would have an ignore case flag like mentioned in the MSDN doc, but it seems this is not valid for generic dictionaries.

Is there a way to get the value of that dictionary ignoring the key case? Is there a better workaround than creating a new copy of the dictionary with the proper StringComparer.OrdinalIgnoreCase parameter?

like image 332
TocToc Avatar asked Nov 05 '12 10:11

TocToc


People also ask

How do you make a dictionary case-insensitive?

In the Dictionary constructor you can specify how keys are compared. For string keys, the default is a case sensitive comparison. To make it case insensitive, you can pass in StringComparer. InvariantCultureIgnoreCase.

Is Dictionary containsKey case sensitive C#?

The default constructor of C# Dictionary class constructs a Dictionary object, in which the keys are case sensitive. So when you insert data pairs <Key, Value> and <key, Value>, they are regarded as two different items.

Are python dictionary keys case sensitive?

Dictionary Keys Are Case-Sensitive : Dictionary Key « Dictionary « Python.

Is containsKey case sensitive Java?

I want to know whether a particular key is present in a HashMap, so i am using containsKey(key) method. But it is case sensitive ie it does not returns true if there is a key with Name and i am searching for name.


2 Answers

There's no way to specify a StringComparer at the point where you try to get a value. If you think about it, "foo".GetHashCode() and "FOO".GetHashCode() are totally different so there's no reasonable way you could implement a case-insensitive get on a case-sensitive hash map.

You can, however, create a case-insensitive dictionary in the first place using:-

var comparer = StringComparer.OrdinalIgnoreCase; var caseInsensitiveDictionary = new Dictionary<string, int>(comparer); 

Or create a new case-insensitive dictionary with the contents of an existing case-sensitive dictionary (if you're sure there are no case collisions):-

var oldDictionary = ...; var comparer = StringComparer.OrdinalIgnoreCase; var newDictionary = new Dictionary<string, int>(oldDictionary, comparer); 

This new dictionary then uses the GetHashCode() implementation on StringComparer.OrdinalIgnoreCase so comparer.GetHashCode("foo") and comparer.GetHashcode("FOO") give you the same value.

Alternately, if there are only a few elements in the dictionary, and/or you only need to lookup once or twice, you can treat the original dictionary as an IEnumerable<KeyValuePair<TKey, TValue>> and just iterate over it:-

var myKey = ...; var myDictionary = ...; var comparer = StringComparer.OrdinalIgnoreCase; var value = myDictionary.FirstOrDefault(x => String.Equals(x.Key, myKey, comparer)).Value; 

Or if you prefer, without the LINQ:-

var myKey = ...; var myDictionary = ...; var comparer = StringComparer.OrdinalIgnoreCase; int? value; foreach (var element in myDictionary) {   if (String.Equals(element.Key, myKey, comparer))   {     value = element.Value;     break;   } } 

This saves you the cost of creating a new data structure, but in return the cost of a lookup is O(n) instead of O(1).

like image 146
Iain Galloway Avatar answered Sep 30 '22 01:09

Iain Galloway


For you LINQers out there that never use a regular dictionary constructor

myCollection.ToDictionary(x => x.PartNumber, x => x.PartDescription, StringComparer.OrdinalIgnoreCase) 
like image 45
Derpy Avatar answered Sep 30 '22 01:09

Derpy