Reputation: 34609
When getting a key from a Dictionary you're not sure exists, you would usually use TryGetValue
instead of ContainsKey
+ the get indexer to avoid the overhead of checking the key twice. In other words, this:
string password;
if (accounts.TryGetValue(username, out password))
{
// use the password
}
would be preferred to this:
if (accounts.ContainsKey(username))
{
string password = accounts[username];
}
What if I wanted to check if a key already existed before setting it to a value? For example, I would want 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!");
}
vs
// this doesn't exist
if (!accounts.TrySetValue(username, password))
{
Console.WriteLine("Username is taken!");
}
Is there a more performant alternative to ContainsKey
and Add
that does this?
Upvotes: 15
Views: 60017
Reputation: 21
I know i am late to this, but you can use a trick and store the count before the indexer set and check the count after the indexer set. If the counts are the same then you have overridden the key otherwise you have 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;
}
Upvotes: 2
Reputation: 127603
If you think inserting a new name will be the common case and attempting to insert a duplicate will be the rare case you may just want to use the overhead of catching a exception.
try
{
accounts.Add(username, password);
}
catch (ArgumentException)
{
Console.WriteLine("Username is taken!");
}
If you call Add
with a existing key a ArgumentException
will be thrown. Even if you have frequent duplicates this will still be likely more performant than your ContainsKey
check.
Upvotes: 6
Reputation: 117154
I tend to write my own extensions as needed.
For example, GetValueOrDefault
like this:
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 like this:
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 ([email protected](key))
{
@this[key] = value;
}
}
Upvotes: 5