通用字典的不区分大小写的访问

时间:2012-11-05 10:42:05

标签: c# generics dictionary

我有一个使用托管dll的应用程序。其中一个dll返回一个通用字典:

Dictionary<string, int> MyDictionary;  

字典包含大小写的键。

另一方面,我得到一个潜在密钥列表(字符串),但我不能保证这种情况。我试图使用键获取字典中的值。但当然,由于案件不匹配,以下情况会失败:

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

我希望TryGetValue会有一个像MSDN doc中提到的 ignore case 标志,但似乎这对通用字典无效。

有没有办法让字典的值忽略关键案例? 有没有比使用正确的 StringComparer.OrdinalIgnoreCase 参数创建字典的新副本更好的解决方法?

4 个答案:

答案 0 :(得分:418)

您无法在尝试获取值时指定StringComparer。如果您考虑一下,"foo".GetHashCode()"FOO".GetHashCode()完全不同,那么就没有合理的方法可以在区分大小写的哈希映射上实现不区分大小写的get。

但是,您可以使用以下方法创建不区分大小写的字典: -

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

或者使用现有区分大小写的字典的内容创建一个新的不区分大小写的字典(如果您确定没有案例冲突): -

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

这个新词典然后使用GetHashCode()上的StringComparer.OrdinalIgnoreCase实现,因此comparer.GetHashCode("foo")comparer.GetHashcode("FOO")会为您提供相同的值。

或者,如果字典中只有少数元素,并且/或者您只需要查找一次或两次,则可以将原始字典视为IEnumerable<KeyValuePair<TKey, TValue>>,然后迭代它: -

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

或者如果你愿意,没有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;
  }
}

这可以节省创建新数据结构的成本,但作为回报,查找的成本是O(n)而不是O(1)。

答案 1 :(得分:23)

对于那些从不使用常规字典构造函数的LINQers:

myCollection.ToDictionary(x => x.PartNumber, x => x.PartDescription, StringComparer.OrdinalIgnoreCase)

答案 2 :(得分:9)

它不是很优雅但是如果你不能改变字典的创建,而你所需要的只是一个肮脏的黑客,那怎么样:

var item = MyDictionary.Where(x => x.Key.ToLower() == MyIndex.ToLower()).FirstOrDefault();
    if (item != null)
    {
        TheValue = item.Value;
    }

答案 3 :(得分:1)

有更简单的方法:

using System;
using System.Collections.Generic;
....
var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);