web-dev-qa-db-ja.com

追加する前にキーがディクショナリに存在するかどうかを確認する最良の方法は?

存在するかどうかわからないディクショナリからキーを取得する場合、通常、TryGetValue + get indexerの代わりにContainsKeyを使用して、キーを2回チェックするオーバーヘッドを回避します。言い換えれば、これ:

string password;
if (accounts.TryGetValue(username, out password))
{
    // use the password
}

これよりも望ましいでしょう:

if (accounts.ContainsKey(username))
{
    string password = accounts[username];
}

キーを値に設定する前に既に存在しているかどうかを確認したい場合はどうすればよいですか?たとえば、新しいパスワードで上書きする前に、ユーザー名が存在するかどうかを確認したいと思います。

if (!accounts.ContainsKey(username))
{
    accounts.Add(username, password);
}
else
{
    Console.WriteLine("Username is taken!");
}

// this doesn't exist
if (!accounts.TrySetValue(username, password))
{
    Console.WriteLine("Username is taken!");
}

これを行うContainsKeyおよびAddの代わりにパフォーマンスがありますか?

10
James Ko

オーバーライドしたくない場合は、TryGetValueのような独自の拡張メソッドを記述する方が良いと思います。標準的な方法はありません。

OR

CuncurrentDictionaryを使用します。 TryAdd メソッドがありますが、同期のオーバーヘッドが発生します。

だから、簡単な答え-いいえ、そのような方法はありません。

5
Backs

新しい名前の挿入が一般的なケースであり、重複を挿入しようとするのはまれなケースだと思う場合は、例外をキャッチするオーバーヘッドを使用したいだけです。

try
{
    accounts.Add(username, password);
}
catch (ArgumentException)
{
    Console.WriteLine("Username is taken!");
}

既存のキーでAddを呼び出すと、ArgumentExceptionがスローされます。重複が頻繁にある場合でも、ContainsKeyチェックよりもパフォーマンスが高い可能性があります。

4

必要に応じて独自の拡張機能を作成する傾向があります。

たとえば、GetValueOrDefaultは次のようになります。

public static V GetValueOrDefault<K, V>(this IDictionary<K, V> @this, K key, Func<V> @default)
{
    return @this.ContainsKey(key) ? @this[key] : @default();
}

次のように使用できます。

var password = accounts.GetValueOrDefault(username, () => null);
if (password != null)
{
    //do stuff
}

またはSetValueIfExists

public static V SetValueIfExists<K, V>(this IDictionary<K, V> @this, K key, V value)
{
    if (@this.ContainsKey(key))
    {
        @this[key] = value;
    }
}

またはSetValueIfNotExists

public static V SetValueIfNotExists<K, V>(this IDictionary<K, V> @this, K key, V value)
{
    if ([email protected](key))
    {
        @this[key] = value;
    }
}
4
Enigmativity

私はこれに遅れていることを知っていますが、インデクサーが設定される前にトリックを使用してカウントを保存し、インデクサーが設定された後にカウントを確認できます。カウントが同じ場合は、キーをオーバーライドしています。それ以外の場合は、新しいマッピングを追加しています。

public static bool AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> 
    dictionary, TKey key, TValue value)
{
    var countBefore = dictionary.Count;
    dictionary[key] = value;
    return countBefore != dictionary.Count;
}
2
MaximGurschi