1

I have a case Sensitive dictionary,

 Dictionary<string, uint> itemNames = new Dictionary<string, uint>(StringComparer.Ordinal);

So I can have case sensitive keys in this dictionary.

For example I can have below key value pairs,

  1. { test, 10 }
  2. { TEST, 20 }
  3. { test1, 30 }
  4. { test2, 40 }

...

When someone passes key, I want to retrieve the value. The retrieval should be partially case insensitive which means, If exact case is matched then return the case sensitive result, if case sensitive key doesn't exists then retrieve case insensitive key value.

For example, with the above values inserted in the dictionary

If user passes key as "TEST" I need to return 20.

If user passes key as "TEST1" , the case sensitive key is not found so I need to return 30.

How to achieve this in C# ?

Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
srajeshnkl
  • 883
  • 3
  • 16
  • 49
  • 2
    If I ask for "teSt", should I get 10 or 20? – Jeroen Mostert Jun 28 '17 at 06:48
  • @JeroenMostert, either of the value is fine. probably first best match can be returned. so 10. – srajeshnkl Jun 28 '17 at 06:50
  • Adding on @JeroenMostert comment, this kind of mixture is never good. Decide if you have case sensitive keys or not. – Ofir Winegarten Jun 28 '17 at 06:50
  • @OfirWinegarten Yes, one way you are right. but my requirement is to have case sensitive dictionary but when retrieving values the preference is for best match and if not at least return case insensitive. – srajeshnkl Jun 28 '17 at 06:52
  • You could maintain a second dictionary that maps the case-insensitive key to "a" case-sensitive key in the first dictionary (or directly to the value, depending on what's more convenient). Con: maintaining two dictionaries is more difficult. Pro: lookups are still O(1) (as opposed to any solution that iterates through the keys). – Jeroen Mostert Jun 28 '17 at 06:57
  • Check extended answer here https://stackoverflow.com/questions/13230414/case-insensitive-access-for-generic-dictionary – OlegI Jun 28 '17 at 07:02
  • Does this answer your question? [Case insensitive access for generic dictionary](https://stackoverflow.com/questions/13230414/case-insensitive-access-for-generic-dictionary) – Michael Freidgeim Sep 22 '22 at 02:07

2 Answers2

2

You should first use TryGetValue to check if there is an item. If not, select the first match:

string key = "test1";
int val;
if (!itemNames.TryGetValue(key, out val))
{
    val = itemNames.FirstOrDefault
                    (k => string.Equals(k.Key, key, StringComparison.OrdinalIgnoreCase)
                    )?.Value ?? 0;
}

Be aware for the performance of this code though. If you have a large dictionary with a lot of misses on the first attempt, a second (case-insensitive) dictionary would be better.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 1
    Be aware for the performance of this code though. If you have a large dictionary, a second (case-insensitive) dictionary would be better. – Patrick Hofman Jun 28 '17 at 07:02
1

Performance wise, the only way to get O(1) average lookup time is to have two dictionaries, where one will use a default comparer, and the other one a case-insensitive one:

// map each string to single item
Dictionary<string, int> CaseSensitive;
    
// map each string to multiple items, case insensitive
Dictionary<string, List<KeyValuePair<string, int>>> CaseInsensitive;

or even

// map each string to single item
Dictionary<string, int> CaseSensitive;
    
// map each string to multiple items, case insensitive, with O(1) lookup time
Dictionary<string, HashSet<KeyValuePair<string, int>>> CaseInsensitive;

Your case insensitive search can then properly return all matches, not just the most recently inserted one.

vgru
  • 49,838
  • 16
  • 120
  • 201