C#中Dictionary实现C++ unordered_map元素增/递加速效方法问询
问题:C#中实现C++ unordered_map自动初始化并递增的高效写法
需要在C#中实现与以下C++代码等效的逻辑:
std::unordered_map<std::string, int> myDictionary; myDictionary["foo"] += 1;
在C++中,当键不存在时会自动将值初始化为0,再递增到1;但C#的Dictionary<string, int>直接使用下标操作时,若键不存在会抛出异常。用户当前采用的写法为:
if (myDictionary.ContainsKey("foo")) { myDictionary["foo"]++; } else { myDictionary.Add("foo", 1); }
用户担忧该写法性能不佳,询问是否有更高效的内置方法实现等效逻辑,或当前写法是否已是最优方案。
回答
最优内置方案:使用TryGetValue
你当前的写法会对字典执行两次键查找(一次ContainsKey,一次下标访问),在高频操作场景下有性能损耗。而TryGetValue只需要一次键查找就能完成逻辑,是更高效的选择:
// 带分支的写法 if (myDictionary.TryGetValue("foo", out int value)) { myDictionary["foo"] = value + 1; } else { myDictionary["foo"] = 1; }
甚至可以简化成更紧凑的形式,利用值类型的默认初始化特性(int默认值为0):
myDictionary.TryGetValue("foo", out int value); myDictionary["foo"] = value + 1;
当键不存在时,value会被设为0,加1后赋值刚好符合“初始化为1”的需求,省去了分支判断。
并发场景的替代方案
如果你的代码需要处理并发写入的场景,可以使用ConcurrentDictionary的AddOrUpdate方法,它内置了线程安全的新增/更新逻辑:
var concurrentDict = new ConcurrentDictionary<string, int>(); concurrentDict.AddOrUpdate("foo", 1, (key, oldValue) => oldValue + 1);
但注意,ConcurrentDictionary是为并发场景设计的,单线程下的性能不如普通Dictionary,非并发场景不建议使用。
结论
单线程场景下,TryGetValue的写法是性能最优的内置方案,比你当前的两次查找写法效率更高;如果不需要并发支持,这就是最佳选择。
内容的提问来源于stack exchange,提问作者Ceyhun
相关产品推荐
相关产品推荐

