2013-05-07 6 views
7

私は、キーがタプルである最初の項目が日付で、2番目の項目が文字列である辞書を持っています。私は大文字小文字を区別しないでください。タプルキーで大文字と小文字を区別しない辞書

キーが単なる文字列だった場合、辞書を宣言するときにStringComparer.OrdinalIgnoreCaseをパラメータとして渡すことができますが、キーがタプルのときは機能しないようです。

タプルの2番目の項目で使用するStringComparerを指定する方法はありますか?

おかげ

答えて

13

あなたがキーのカスタム比較子を指定することができますDictionaryコンストラクタの使用this overload。あなたはこのようになります

IEqualityComparer<Tuple<string, DateTime>> 

を実装するクラスを作成し、これを伴うだろう。ここには、引数のチェックはありません

class CustomEqualityComparer : IEqualityComparer<Tuple<string, DateTime>> 
{ 

    public bool Equals(Tuple<string, DateTime> lhs, Tuple<string, DateTime> rhs) 
    { 
     return 
      StringComparer.CurrentCultureIgnoreCase.Equals(lhs.Item1, rhs.Item1) 
     && lhs.Item2 == rhs.Item2; 
    } 


    public int GetHashCode(Tuple<string, DateTime> tuple) 
    { 
     return StringComparer.CurrentCultureIgnoreCase.GetHashCode(tuple.Item1) 
      ^tuple.Item2.GetHashCode(); 
    } 
} 

ので、本番コードとして扱いしないでください

。また、 EqualsGetHashCodeの実装が、2つのタプルが等しいと比較される場合は、 の同じ重要な条件を満たし、同じハッシュコードを持つように注意する必要があります。カスタムテキストの比較を扱うときは、細心の注意を払わずにバグを導入するのは簡単です。たとえば、上記の ToLowerの代わりに ToLowerInvariantを使用すると、バグになることがあります。

+0

を作成するために、@ジョンのコードを使用ハッシュコードは、あなたが言及したバグを避けるのに最も効果的です。私は提案された修正で答えを編集しました。あなたがそれを気に入らなければ元に戻してください。 – dtb

+0

@dtb:これはIMOでも一貫性の向上であるため、間違いなく元に戻すことはありません。ありがとう! – Jon

1

比較は大文字と小文字を区別しないので、タプルを作成するときにtoLower/toUpperメソッドを文字列側で使用して、検索に使用されたタプルの文字列を常に上または下にします/辞書のエントリを比較する。

+1

文字列を大文字または小文字に変換して比較することは、一部の文化では正しく機能しません。 StringComparer.CurrentCultureIgnoreCaseなどのStringComparerを使用する方がよいでしょう。 – dtb

0

私はDictionary<Tuple<>>ラッパーでこれを必要なので、私は平等のためにして取得するためにチェックするために、同じStringComparerを使用してジェネリック版

public class TupleEqualityComparer<T1, T2> : IEqualityComparer<Tuple<T1, T2>> 
{ 
    private IEqualityComparer<T1> comparer1; 
    private IEqualityComparer<T2> comparer2; 

    public TupleEqualityComparer(IEqualityComparer<T1> comparer1, IEqualityComparer<T2> comparer2) 
    { 
     this.comparer1 = comparer1 ?? EqualityComparer<T1>.Default; 
     this.comparer2 = comparer2 ?? EqualityComparer<T2>.Default; 
    } 

    public bool Equals(Tuple<T1, T2> lhs, Tuple<T1, T2> rhs) 
    { 
     return comparer1.Equals(lhs.Item1, rhs.Item1) && comparer2.Equals(lhs.Item2, rhs.Item2); 
    } 

    public int GetHashCode(Tuple<T1, T2> tuple) 
    { 
     return comparer1.GetHashCode(tuple.Item1)^comparer2.GetHashCode(tuple.Item2); 
    } 

} 

public class Dictionary<TKey1, TKey2, TValue> : Dictionary<Tuple<TKey1, TKey2>, TValue>() 
{ 
    public Dictionary() : base() { } 
    public Dictionary(IEqualityComparer<TKey1> comparer1, IEqualityComparer<TKey2> comparer2) : base(new TupleEqualityComparer<TKey1, Tkey2>(comparer1, comparer2) { } 

    public TValue this[TKey1 key1, TKey2 key2] 
    { 
     get { return base[Tuple.Create(key1, key2)]; } 
    } 

    public void Add(TKey1 key1, TKey2 key2, TValue value) 
    { 
     base.Add(Tuple.Create(key1, key2), value); 
    } 

    public bool ContainsKey(TKey1 key1, TKey2 key2) 
    { 
     return base.ContainsKey(Tuple.Create(key1, key2)); 
    } 

    public bool TryGetValue(TKey1 key1, TKey2 key2, out TValue value) 
    { 
     return base.TryGetValue(Tuple.Create(key1, key2), out value); 
    } 
} 

使用

var dict = new Dictionary<string, DateTime, int>(
    StringComparer.OrdinalIgnoreCase, null); 
dict.Add("value1", DateTime.Now, 123); 
Assert.IsTrue(dict.ContainsKey("VALUe1")); 
関連する問題