Edward Chen
Posted on November 22, 2019
Recently I came across an interesting problem that threw me off initially. Now let me preface this with the fact that I have been using C# daily for almost three years now so I am by no means an expert like Jon Skeet but I am no beginner. If you want a TL;DR, as always scroll to the bottom.
So the problem was pretty simple, print out a list of the number of occurrences in an array.
var dict = new Dictionary<int, int>();
var nums = new int[]{1,1,2,3,3,3,4};
foreach (var num in nums)
{
if(dict.TryGetValue(num,out int val)){
dict[num] += 1;
}
else{
dict.Add(num,1);
}
}
foreach (var num in dict)
{
Console.WriteLine($"Key: {num.Key}, Occurence: {num.Value}");
}
This prints out what you would expect:
However when I tried to use the [key]=value
way, I got an error, the ever so common KeyNotFoundException
.
var dict = new Dictionary<int, int>();
var nums = new int[]{1,1,2,3,3,3,4};
foreach (var num in nums)
{
dict[num] += 1;
}
foreach (var num in dict)
{
Console.WriteLine($"Key: {num.Key}, Occurence: {num.Value}");
}
That was odd to me because I had always thought that was equivalent to Add or update. Of course I could have gone my merry way and taken a mental note to always use the Add method in combination with TryGetValue which would have caught the exception but by golly, I had to know I was not going insane here with such a simple task like adding a value to a dictionary.
After digging into the reference source, the two look pretty identical.
public void Add(TKey key, TValue value)
{
this.Insert(key, value, true);
}
public TValue this[TKey key]
{
get
{
int index = this.FindEntry(key);
if (index >= 0)
{
return this.entries[index].value;
}
ThrowHelper.ThrowKeyNotFoundException();
return default(TValue);
}
set
{
this.Insert(key, value, false);
}
}
The only difference was the third argument but after taking a look at Insert, that is really only used to throw an exception if there is a duplicate Key.
But then it dawned on me that I am shaving the yak and I needed to take a step. Lo and behold, with that step back I realized that it was the operator precedence. The issue wasn't with the dictionary, it was with the +=
that I was doing. Because of that, the code was doing a get and then setting the value to an increment of plus one. However, the value doesn't exist which is where the KeyNotFound exception was thrown.
Finally, I can push off the imposter syndrome for a little while longer. Thank you for reading and I hope everyone has fun programming!
TL;DR
First off, if I had checked StackOverflow first, I would have realized many people have thought of this and there's an excellent answer to this here.
But to summarize, [key]=value is not really Add or Update in my case because of the order of precedence with operators. Due to dict[num] += 1
, the code is doing a get
on the num
value in the dictionary and throws an exception because the value does not exist.
Posted on November 22, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.