Case insensitive access for generic dictionary

前端 未结 4 636
梦毁少年i
梦毁少年i 2020-11-28 02:31

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

Dictionary MyDictionary;  

相关标签:
4条回答
  • 2020-11-28 02:55

    Its not very elegant but in case you cant change the creation of dictionary, and all you need is a dirty hack, how about this:

    var item = MyDictionary.Where(x => x.Key.ToLower() == MyIndex.ToLower()).FirstOrDefault();
        if (item != null)
        {
            TheValue = item.Value;
        }
    
    0 讨论(0)
  • 2020-11-28 03:06

    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).

    0 讨论(0)
  • 2020-11-28 03:15

    There is much simpler way:

    using System;
    using System.Collections.Generic;
    ....
    var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    
    0 讨论(0)
  • 2020-11-28 03:16

    For you LINQers out there who never use a regular dictionary constructor:

    myCollection.ToDictionary(x => x.PartNumber, x => x.PartDescription, StringComparer.OrdinalIgnoreCase)
    
    0 讨论(0)
提交回复
热议问题