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.
Top comments (1)
More accurately:
[key]=value
is still an "add or update", butx =+ y
meansx = x + y
- "get x, add y to it, and set that value to x" - so yeah, it's the operator.This is also true with
dict[key]=value++
and++dict[key]=value
.