在添加密钥之前检查字典中是否存在密钥的最佳方法?

时间:2015-08-07 04:50:50

标签: c# performance dictionary data-structures hashtable

从字典中获取密钥时,您确定不存在,通常使用TryGetValue代替ContainsKey + get索引器,以避免两次检查密钥的开销。换句话说,这个:

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!");
}

VS

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

ContainsKeyAdd是否有更多高性能替代方案?

4 个答案:

答案 0 :(得分:5)

如果您不想覆盖,我认为编写自己的扩展方法(例如TryGetValue)会更好。没有标准方法。

OR

使用CuncurrentDictionary,它有TryAdd方法,但您在同步时会有开销。

所以,简单的答案 - 不,没有这样的方法。

答案 1 :(得分: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 (!@this.ContainsKey(key))
    {
        @this[key] = value;
    }
}

答案 2 :(得分:3)

如果您认为插入新名称是常见情况,并且尝试插入副本将是极少数情况下您可能只想使用捕获异常的开销。

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

如果您使用现有密钥致电Add,则会引发ArgumentException。即使您经常重复,这仍然可能比ContainsKey检查更有效。

答案 3 :(得分:2)

我知道我迟到了,但您可以使用技巧并在索引器设置之前存储计数,并在索引器设置后检查计数。如果计数相同,那么您已覆盖密钥,否则您已添加新映射:

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;
}