What is more efficient: Dictionary TryGetValue or ContainsKey+Item?
Solution 1:
TryGetValue
will be faster.
ContainsKey
uses the same check as TryGetValue
, which internally refers to the actual entry location. The Item
property actually has nearly identical code functionality as TryGetValue
, except that it will throw an exception instead of returning false.
Using ContainsKey
followed by the Item
basically duplicates the lookup functionality, which is the bulk of the computation in this case.
Solution 2:
A quick benchmark shows that TryGetValue
has a slight edge:
static void Main() {
var d = new Dictionary<string, string> {{"a", "b"}};
var start = DateTime.Now;
for (int i = 0; i != 10000000; i++) {
string x;
if (!d.TryGetValue("a", out x)) throw new ApplicationException("Oops");
if (d.TryGetValue("b", out x)) throw new ApplicationException("Oops");
}
Console.WriteLine(DateTime.Now-start);
start = DateTime.Now;
for (int i = 0; i != 10000000; i++) {
string x;
if (d.ContainsKey("a")) {
x = d["a"];
} else {
x = default(string);
}
if (d.ContainsKey("b")) {
x = d["b"];
} else {
x = default(string);
}
}
}
This produces
00:00:00.7600000
00:00:01.0610000
making the ContainsKey + Item
access about 40% slower assuming an even blend of hits and misses.
Moreover, when I change the program to always miss (i.e. always looking up "b"
) the two versions become equally fast:
00:00:00.2850000
00:00:00.2720000
When I make it "all hits", however, the TryGetValue
remains a clear winner:
00:00:00.4930000
00:00:00.8110000
Solution 3:
Since none of the answers thus far actually answer the question, here is an acceptable answer I found after some research:
If you decompile TryGetValue you see that it’s doing this:
public bool TryGetValue(TKey key, out TValue value)
{
int index = this.FindEntry(key);
if (index >= 0)
{
value = this.entries[index].value;
return true;
}
value = default(TValue);
return false;
}
whereas the ContainsKey method is:
public bool ContainsKey(TKey key)
{
return (this.FindEntry(key) >= 0);
}
so TryGetValue is just ContainsKey plus an array lookup if the item is present.
Source
It appears that TryGetValue will be almost twice as fast as ContainsKey+Item combination.
Solution 4:
Who cares :-)
You're probably asking because TryGetValue
is a pain to use - so encapsulate it like this with an extension method.
public static class CollectionUtils
{
// my original method
// public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key)
// {
// V ret;
// bool found = dic.TryGetValue(key, out ret);
// if (found)
// {
// return ret;
// }
// return default(V);
// }
// EDIT: one of many possible improved versions
public static TValue GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key)
{
// initialized to default value (such as 0 or null depending upon type of TValue)
TValue value;
// attempt to get the value of the key from the dictionary
dictionary.TryGetValue(key, out value);
return value;
}
Then just call :
dict.GetValueOrDefault("keyname")
or
(dict.GetValueOrDefault("keyname") ?? fallbackValue)