web-dev-qa-db-ja.com

汎用辞書の大文字と小文字を区別しないアクセス

マネージdllを使用するアプリケーションがあります。これらのdllの1つは、汎用辞書を返します。

Dictionary<string, int> MyDictionary;  

辞書には、大文字と小文字のキーが含まれています。

別の面では、潜在的なキー(文字列)のリストを取得していますが、ケースを保証することはできません。キーを使用して辞書の値を取得しようとしています。ただし、大文字と小文字が一致しないため、もちろん次は失敗します。

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

TryGetValueにignore caseフラグ MSDN doc に記載されているようなフラグがあることを期待していましたが、これは一般的な辞書には有効ではないようです。

キーケースを無視してその辞書の値を取得する方法はありますか?適切なStringComparer.OrdinalIgnoreCaseパラメーターで辞書の新しいコピーを作成するよりも良い回避策はありますか?

204
TocToc

値を取得しようとする時点で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);

この新しいディクショナリは、StringComparer.OrdinalIgnoreCaseGetHashCode()実装を使用するため、comparer.GetHashCode("foo")comparer.GetHashcode("FOO")は同じ値を提供します。

あるいは、辞書に数個の要素しかない場合、および/または1回または2回検索するだけでよい場合、元の辞書を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(1)ではなくO(n)です。

424
Iain Galloway

通常のディクショナリコンストラクターを決して使用しないLINQersの場合:

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

非常にエレガントではありませんが、辞書の作成を変更できない場合、必要なのは汚いハックだけです。これはどうですか:

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