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

问题描述 投票:0回答:4

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

Dictionary<string, int> MyDictionary;  

字典包含大写和小写的键。

另一方面,我得到了潜在键(字符串)的列表,但我不能保证这种情况。我正在尝试使用键获取字典中的值。但是,由于我的大小写不匹配,以下操作当然会失败:

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

我希望 TryGetValue 会有一个 ignore case 标志,如 MSDN 文档中提到的那样,但似乎这对于通用词典无效。

有没有办法忽略关键情况来获取该字典的值? 有没有比使用正确的 StringComparer.OrdinalIgnoreCase 参数创建字典的新副本更好的解决方法?

c# generics dictionary
4个回答
768
投票

无法在尝试获取值时指定

StringComparer
。默认情况下,
"foo".GetHashCode()
"FOO".GetHashCode()
完全不相关,这意味着没有合理的方法可以在区分大小写的哈希映射上实现不区分大小写的获取。这些项目已根据其(区分大小写)哈希码进行存储。

但是,您可以首先使用以下命令创建不区分大小写的字典:-

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


76
投票

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

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

44
投票

还有更简单的方法:

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

12
投票

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

var item = MyDictionary.Where(x => x.Key.ToLower() == MyIndex.ToLower()).FirstOrDefault();
    if (item != null)
    {
        TheValue = item.Value;
    }
© www.soinside.com 2019 - 2024. All rights reserved.