Edward Chen

ContactAbout

C# Dictionary: Add or [key]=value?

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.