Best way to check if a key exists in a dictionary before adding it?

When retrieving a key from a dictionary that you are not sure about, you usually use TryGetValue instead of ContainsKey + get indexer to avoid the overhead of checking the key twice. In other words, it is:

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

would be preferable:

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

What if I want to check if the key existed before its value? For example, I would like to check if a username existed before overwriting it with a new password:

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

against

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

Is there a better alternative to ContainsKey and Add that does this?

+7
performance dictionary hashtable c # data-structures
source share
4 answers

If you do not want to override, I think it is better to write your own extension method, for example TryGetValue . There is no standard method.

OR

Use CuncurrentDictionary, it is TryAdd , but you will have synchronization overhead.

So, the simple answer is no, there is no such method.

+5
source share

If you think that inserting a new name will be common, and trying to insert a duplicate will be a rare case, you can simply use the overhead to eliminate the exception.

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

If you call Add with an existing key, an ArgumentException will be ArgumentException . Even if you have frequent duplicates, it will still be more efficient than checking the ContainsKey .

+4
source share

I try to write my own extensions as needed.

For example, GetValueOrDefault as follows:

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

It can be used as follows:

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

Or SetValueIfExists :

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

Or SetValueIfNotExists :

 public static V SetValueIfNotExists<K, V>(this IDictionary<K, V> @this, K key, V value) { if ( !@this.ContainsKey (key)) { @this[key] = value; } } 
+3
source share

I know that I am late for this, but you can use the trick and store the counter before the indexer is installed, and check the counter after installing the indexer. If the counts match, then you redefined the key, otherwise you added a new mapping:

 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; } 
0
source share

All Articles