web-dev-qa-db-ja.com

KeyValuePair <>をDictionary <>から直接取得する

私は_System.Collections.Generic.Dictionary<A, B> dict_を持っています。AとBはクラスで、インスタンス_A a_(dict.ContainsKey(a)はtrue)があります。

辞書から直接aを含むKeyValuePairを取得することは可能ですか?
または、新しいKeyValuePairを作成する必要がありますか:new KeyValuePair<A, B>(a, dict[a])

34
user200783

新しいKeyValuePairを作成する必要があります1 -ただし、KVPはいずれにしても値型(構造体)であることを忘れないでください。そのため、これを実行することで新しい非効率性を導入しているわけではありません。いずれにしても、KVPを返すメソッドはコピーを作成します。インスタンスを直接作成するだけです。

必要に応じて、拡張メソッドをIDictionary<TKey, TValue>にいつでも追加できます。

public static KeyValuePair<TKey, TValue> GetEntry<TKey, TValue>
    (this IDictionary<TKey, TValue> dictionary,
     TKey key)
{
    return new KeyValuePair<TKey, TValue>(key, dictionary[key]);
}

コメントに記載されているように、ディクショナリに格納されているキーがsameでなく、意味的に等しいだけである可能性があります-IEqualityComparer(大文字と小文字を区別しないディクショナリなど)。その場合、上記のコードはディクショナリの実際のエントリではなく、検索のために指定したキーを持つエントリを返します。残念ながら、元のキーを見つける効率的な方法はありません-辞書を反復処理する必要があります:(


1 辞書エントリを反復処理して適切なエントリをその方法で見つけることができることは知っていましたが、O(1).

41
Jon Skeet

なので Dictionary<TKey, TValue>実装IEnumerable<KeyValuePair<TKey, TValue>>、linqを使用できます:

var pair = _dictionary.SingleOrDefault(p => p.Key == myKey);
18
Oliver Hanappi

この方法では"IPHone"にアクセスできません:

var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
               {
                   { "IPHone", "TCP/IP honing tools" }
               };

Console.WriteLine(dict["iPhone"]); // "TCP/IP honing tools"
Console.WriteLine( ??? ); // "IPHone"

現在のAPIではO(1)ソリューションはないようですが、すべてのエントリをループすることで機能します。

var keyValue = dict.First(p => dict.Comparer.Equals(p.Key, "iPhone"));

Console.WriteLine(keyValue.Key); // "IPHone"
Console.WriteLine(keyValue.Value); // "TCP/IP honing tools"

またはレイジーの拡張として:

[Pure]
public static KeyValuePair<TKey, TValue> GetEntry<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
{
    var comparer = dictionary.Comparer;
    return dictionary.FirstOrDefault(p => comparer.Equals(p.Key, key));
}
1
johv

私のために myDict.AsEnumerableします...

0
Silvan Hofer